#18931: Boost shortest paths
-------------------------------------+-------------------------------------
       Reporter:  borassi            |        Owner:
           Type:  enhancement        |       Status:  needs_work
       Priority:  major              |    Milestone:  sage-6.9
      Component:  graph theory       |   Resolution:
       Keywords:  Boost, shortest    |    Merged in:
  paths, Bellman-Ford, Johnson       |    Reviewers:
        Authors:  Michele Borassi    |  Work issues:
Report Upstream:  N/A                |       Commit:
         Branch:                     |  4897c8e27daa7c7939827524bec312ff8f39b3b7
  u/borassi/boost_shortest_paths     |     Stopgaps:
   Dependencies:  #18910, #18938     |
-------------------------------------+-------------------------------------

Comment (by borassi):

 Hello!

 Thank you very much for your comments. I think we should discuss some
 issues, and I would like to hear also Nathann's opinion, because I think
 shortest paths are very important.

 In the following, I tried to support the choices I made in the version of
 the code that will soon be uploaded: feel free to disagree!

 Best,

 Michele

 Replying to [comment:5 dcoudert]:

 > Hello,
 >
 > the output of the method is correct and already faster than networkx on
 small graphs. Excellent!

 :)

 > do you also plan to add `G.shortest_path()` ?

 Ups, you are right. I am quite sure that the bidirectional Dijkstra that
 is already implemented is better than Boost Dijkstra algorithm (hence, I
 did not include it), but I did not think that we may add an algorithm that
 works with negative weights.

 Now I have done it! However, I still have doubts on what happens if we run
 Dijkstra with negative weights. Before this patch, the result was
 completely unreliable:

 {{{
 sage: G = DiGraph([(0,1,1),(1,2,1),(0,3,1000),(3,4,-3000), (4,2,1000)])
 sage: G.shortest_path_length(0, 2, by_weight=True, algorithm='Bellman-
 Ford_Boost')
 -1000
 sage: G.shortest_path_length(0, 2, by_weight=True)
 2
 }}}
 However, reading all edges to check if there are negative weights may
 increase drastically the running-time, since the algorithm is sublinear.
 Hence, I just added a note and two examples to show the issue. Moreover,
 now, if Dijkstra algorithm finds an edge with negative weight, an error is
 raised (however, if the error is not raised, it doesn't mean that the path
 is correct, as shown by the previous example). Do you think it is a good
 solution?

 > For all pairs shortest paths:
 > - we don't have predecessors with `Johnson_Boost`

 Yes, it is documented in the OUTPUT section of the documentation.
 Unfortunately Boost does not have this feature, and recomputing
 predecessors from distances is too time-consuming. For this reason, I
 still use Floyd-Warshall algorithm as default, and I use the faster
 Johnson algorithm only if paths are not needed (for instance, when
 computing eccentricities).

 > - distance to unreacheable vertices should be set to +Infinity to be
 consistent with other methods.

 I think we should discuss a bit more this point. My proposal is to do the
 converse, that is, to remove from dictionaries all unreachable vertices:
 this is what I have done in this commit. I have some reasons to support
 this solution: please, let me know if you think they are sufficient!

 First of all, this task is memory-consuming, and saving memory for graphs
 which are not connected might be a good choice. Also the running-time is
 decreased, and the code is simplified. Furthermore, before, the
 predecessor of the starting vertex (None) was the same as the predecessor
 of unreachable vertices. This might be unwanted, if the user writes
 something like:

 {{{
 distance_v_w = 0
 while pred[w] is not None:
     distance_v_w = distance_v_w + 1
     w = pred[w]

 }}}
 With this code, the distance from an unreachable vertex is 0 (while I
 think we should distinguish between "I have already reached the starting
 vertex" and "I cannot reach the starting vertex").

 Moreover, the `shortest_paths` and `shortest_path_lengths` routines
 already follow this policy: adapting the `shortest_path_all_pairs` routine
 is good for consistency, to simplify the code and to reduce the running-
 time when `shortest_path_all_pairs` calls `shortest_paths`. Finally, one
 might easily imitate the other behavior by writing `d[v].get(w,Infinity)`
 instead of `d[v][w]`.

--
Ticket URL: <http://trac.sagemath.org/ticket/18931#comment:6>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sage-trac.
For more options, visit https://groups.google.com/d/optout.

Reply via email to