~ubuntu-branches/ubuntu/trusty/python-networkx/trusty

« back to all changes in this revision

Viewing changes to networkx/algorithms/shortest_paths/weighted.py

  • Committer: Bazaar Package Importer
  • Author(s): Sandro Tosi
  • Date: 2010-12-10 23:50:27 UTC
  • mfrom: (1.2.4 upstream) (5.1.4 sid)
  • Revision ID: james.westby@ubuntu.com-20101210235027-b2supdwo0ad39d3s
Tags: 1.3-1
* New upstream release
* debian/patches/changeset_r1745.diff
  - dropped, available in upstream release
* debian/patches/10_doc_relocation
  - refreshed patch for new upstream code
* debian/control
  - upstream code is now compatible with 2.6 or later only
  - bump Standards-Version to 3.9.1 (no changes needed)
* debian/{control, rules}
  - run unittests at build time, b-d on python-nose added
* debian/copyright
  - removed reference to /usr/share/common-licenses/BSD
* Create a -doc package ; thanks to Yaroslav Halchenko for the report;
  Closes: #567369
  - (d/control) define a new binary package, and add depends on sphinx (>= 1)
  - (d/rules) build documentation, install it into the new -doc package
  - (d/patches/30_use_local_objects.inv) use local copy of remote objects.inv
* debian/{control, rules}
  - moved to dh7 and "reduced" rules file
* debian/rules
  - refer to built code when building doc
* debian/python-networkx-doc.doc-base
  - added doc-base information
* debian/patches/40_add_networkxcss
  - added as patch, since networkx.css is missing from the tarball, but needed
    to display properly HTML documentation
* debian/patches/50_boundary-test-fix.patch
  - upstream patch to restrict node boundary test cases to valid range
* debian/patches/60_remove_svn_refs.diff
  - upstream patch to remove references to old SVN repository (now Mercurial)
* debian/patches/70_set_matplotlib_ps_backend.patch
  - set matplotlib backend to 'PS', so a DISPLAY it's not required and the
    tests can be run in a "reduced" environment

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
"""
 
3
Shortest path algorithms for weighed graphs.
 
4
"""
 
5
__author__ = """\n""".join(['Aric Hagberg <hagberg@lanl.gov>',
 
6
                            'Loïc Séguin-C. <loicseguin@gmail.com>'])
 
7
#    Copyright (C) 2004-2010 by 
 
8
#    Aric Hagberg <hagberg@lanl.gov>
 
9
#    Dan Schult <dschult@colgate.edu>
 
10
#    Pieter Swart <swart@lanl.gov>
 
11
#    All rights reserved.
 
12
#    BSD license.
 
13
 
 
14
__all__ = ['dijkstra_path', 
 
15
           'dijkstra_path_length', 
 
16
           'bidirectional_dijkstra',
 
17
           'single_source_dijkstra_path', 
 
18
           'single_source_dijkstra_path_length',
 
19
           'all_pairs_dijkstra_path', 
 
20
           'all_pairs_dijkstra_path_length',
 
21
           'single_source_dijkstra', 
 
22
           'dijkstra_predecessor_and_distance',
 
23
           'bellman_ford']
 
24
 
 
25
 
 
26
import heapq
 
27
import networkx as nx
 
28
 
 
29
def dijkstra_path(G,source,target, weight = 'weight'):
 
30
    """Returns the shortest path from source to target in a weighted graph G.  
 
31
 
 
32
    Parameters
 
33
    ----------
 
34
    G : NetworkX graph
 
35
 
 
36
    source : node 
 
37
       Starting node
 
38
 
 
39
    target : node 
 
40
       Ending node
 
41
 
 
42
    weight: string, optional       
 
43
       Edge data key corresponding to the edge weight
 
44
       
 
45
    Returns
 
46
    -------
 
47
    path : list
 
48
       List of nodes in a shortest path.
 
49
 
 
50
    Examples
 
51
    --------
 
52
    >>> G=nx.path_graph(5)
 
53
    >>> print(nx.dijkstra_path(G,0,4))
 
54
    [0, 1, 2, 3, 4]
 
55
 
 
56
    Notes
 
57
    ------
 
58
    Uses a bidirectional version of Dijkstra's algorithm.
 
59
    Edge weight attributes must be numerical.
 
60
 
 
61
    See Also
 
62
    --------
 
63
    bidirectional_dijkstra()
 
64
    """
 
65
#    (length,path)=bidirectional_dijkstra(G,source,target) # faster, needs test
 
66
#     return path
 
67
    (length,path)=single_source_dijkstra(G,source, weight = weight)
 
68
    try:
 
69
        return path[target]
 
70
    except KeyError:
 
71
        raise nx.NetworkXError("node %s not reachable from %s"%(source,target))
 
72
 
 
73
 
 
74
def dijkstra_path_length(G,source,target, weight = 'weight'):
 
75
    """Returns the shortest path length from source to target in a weighted graph G.  
 
76
 
 
77
 
 
78
    Parameters
 
79
    ----------
 
80
    G : NetworkX graph, weighted
 
81
 
 
82
    source : node label
 
83
       starting node for path
 
84
 
 
85
    target : node label
 
86
       ending node for path 
 
87
 
 
88
    weight: string, optional       
 
89
       Edge data key corresponding to the edge weight
 
90
 
 
91
    Returns
 
92
    -------
 
93
    length : number
 
94
        Shortest path length.
 
95
       
 
96
    Raises
 
97
    ------
 
98
    NetworkXError
 
99
        If no path exists between source and target.
 
100
 
 
101
    Examples
 
102
    --------
 
103
    >>> G=nx.path_graph(5) # a weighted graph by default
 
104
    >>> print(nx.dijkstra_path_length(G,0,4))
 
105
    4
 
106
    
 
107
    Notes
 
108
    -----
 
109
    Edge weight attributes must be numerical.
 
110
 
 
111
    See Also
 
112
    --------
 
113
    bidirectional_dijkstra()
 
114
 
 
115
    """
 
116
 
 
117
#    (length,path)=bidirectional_dijkstra(G,source,target) # faster, needs test
 
118
#    return length
 
119
    (length,path)=single_source_dijkstra(G,source, weight = weight)
 
120
    try:
 
121
        return length[target]
 
122
    except KeyError:
 
123
        raise nx.NetworkXError("node %s not reachable from %s"%(source,target))
 
124
 
 
125
 
 
126
 
 
127
def bidirectional_dijkstra(G, source, target, weight = 'weight'):
 
128
    """Dijkstra's algorithm for shortest paths using bidirectional search. 
 
129
 
 
130
    Parameters
 
131
    ----------
 
132
    G : NetworkX graph
 
133
 
 
134
    source : node
 
135
       Starting node.
 
136
 
 
137
    target : node
 
138
       Ending node.
 
139
 
 
140
    weight: string, optional       
 
141
       Edge data key corresponding to the edge weight
 
142
 
 
143
    Returns
 
144
    -------
 
145
    length : number
 
146
        Shortest path length.
 
147
 
 
148
    Returns a tuple of two dictionaries keyed by node.
 
149
    The first dicdtionary stores distance from the source.
 
150
    The second stores the path from the source to that node.
 
151
 
 
152
    Raise an exception if no path exists.
 
153
 
 
154
 
 
155
    Raises
 
156
    ------
 
157
    NetworkXError
 
158
        If no path exists between source and target.
 
159
 
 
160
    Examples
 
161
    --------
 
162
    >>> G=nx.path_graph(5)
 
163
    >>> length,path=nx.bidirectional_dijkstra(G,0,4)
 
164
    >>> print(length)
 
165
    4
 
166
    >>> print(path)
 
167
    [0, 1, 2, 3, 4]
 
168
    
 
169
    Notes
 
170
    -----
 
171
    Edge weight attributes must be numerical.
 
172
    Distances are calculated as sums of weighted edges traversed.
 
173
 
 
174
    In practice  bidirectional Dijkstra is much more than twice as fast as 
 
175
    ordinary Dijkstra.
 
176
 
 
177
    Ordinary Dijkstra expands nodes in a sphere-like manner from the
 
178
    source. The radius of this sphere will eventually be the length 
 
179
    of the shortest path. Bidirectional Dijkstra will expand nodes 
 
180
    from both the source and the target, making two spheres of half 
 
181
    this radius. Volume of the first sphere is pi*r*r while the  
 
182
    others are 2*pi*r/2*r/2, making up half the volume. 
 
183
    
 
184
    This algorithm is not guaranteed to work if edge weights
 
185
    are negative or are floating point numbers
 
186
    (overflows and roundoff errors can cause problems). 
 
187
 
 
188
    See Also
 
189
    --------
 
190
    shortest_path
 
191
    shortest_path_length
 
192
    """
 
193
    if source is None or target is None:
 
194
        raise NetworkXException(
 
195
            "Bidirectional Dijkstra called with no source or target")
 
196
    if source == target: return (0, [source])
 
197
    #Init:   Forward             Backward
 
198
    dists =  [{},                {}]# dictionary of final distances
 
199
    paths =  [{source:[source]}, {target:[target]}] # dictionary of paths 
 
200
    fringe = [[],                []] #heap of (distance, node) tuples for extracting next node to expand
 
201
    seen =   [{source:0},        {target:0} ]#dictionary of distances to nodes seen 
 
202
    #initialize fringe heap
 
203
    heapq.heappush(fringe[0], (0, source)) 
 
204
    heapq.heappush(fringe[1], (0, target))
 
205
    #neighs for extracting correct neighbor information
 
206
    if G.is_directed():
 
207
        neighs = [G.successors_iter, G.predecessors_iter]
 
208
    else:
 
209
        neighs = [G.neighbors_iter, G.neighbors_iter]
 
210
    #variables to hold shortest discovered path
 
211
    #finaldist = 1e30000
 
212
    finalpath = []
 
213
    dir = 1
 
214
    while fringe[0] and fringe[1]:
 
215
        # choose direction 
 
216
        # dir == 0 is forward direction and dir == 1 is back
 
217
        dir = 1-dir
 
218
        # extract closest to expand
 
219
        (dist, v )= heapq.heappop(fringe[dir]) 
 
220
        if v in dists[dir]:
 
221
            # Shortest path to v has already been found 
 
222
            continue
 
223
        # update distance
 
224
        dists[dir][v] = dist #equal to seen[dir][v]
 
225
        if v in dists[1-dir]:
 
226
            # if we have scanned v in both directions we are done 
 
227
            # we have now discovered the shortest path
 
228
            return (finaldist,finalpath)
 
229
 
 
230
        for w in neighs[dir](v):
 
231
            if(dir==0): #forward
 
232
                if G.is_multigraph():
 
233
                    minweight=min((dd.get(weight,1)
 
234
                               for k,dd in G[v][w].items()))
 
235
                else:
 
236
                    minweight=G[v][w].get(weight,1)
 
237
                vwLength = dists[dir][v] + minweight #G[v][w].get(weight,1)
 
238
            else: #back, must remember to change v,w->w,v
 
239
                if G.is_multigraph():
 
240
                    minweight=min((dd.get(weight,1)
 
241
                               for k,dd in G[w][v].items()))
 
242
                else:
 
243
                    minweight=G[w][v].get(weight,1)
 
244
                vwLength = dists[dir][v] + minweight #G[w][v].get(weight,1)
 
245
            
 
246
            if w in dists[dir]:
 
247
                if vwLength < dists[dir][w]:
 
248
                    raise ValueError("Contradictory paths found: negative weights?")
 
249
            elif w not in seen[dir] or vwLength < seen[dir][w]:
 
250
                # relaxing        
 
251
                seen[dir][w] = vwLength
 
252
                heapq.heappush(fringe[dir], (vwLength,w)) 
 
253
                paths[dir][w] = paths[dir][v]+[w]
 
254
                if w in seen[0] and w in seen[1]:
 
255
                    #see if this path is better than than the already
 
256
                    #discovered shortest path
 
257
                    totaldist = seen[0][w] + seen[1][w] 
 
258
                    if finalpath == [] or finaldist > totaldist:
 
259
                        finaldist = totaldist
 
260
                        revpath = paths[1][w][:]
 
261
                        revpath.reverse()
 
262
                        finalpath = paths[0][w] + revpath[1:]
 
263
    return False
 
264
 
 
265
 
 
266
#def dijkstra(G,source,target):
 
267
#    return bidirectional_dijkstra(G,source,target)
 
268
 
 
269
 
 
270
def single_source_dijkstra_path(G,source, weight = 'weight'):
 
271
    """Compute shortest path between source and all other reachable nodes for a weighted graph.
 
272
 
 
273
    Parameters
 
274
    ----------
 
275
    G : NetworkX graph
 
276
 
 
277
    source : node
 
278
       Starting node for path. 
 
279
 
 
280
    weight: string, optional       
 
281
       Edge data key corresponding to the edge weight
 
282
 
 
283
    Returns
 
284
    -------
 
285
    paths : dictionary
 
286
       Dictionary of shortest path lengths keyed by target.
 
287
 
 
288
    Examples
 
289
    --------
 
290
    >>> G=nx.path_graph(5)
 
291
    >>> path=nx.single_source_dijkstra_path(G,0)
 
292
    >>> path[4]
 
293
    [0, 1, 2, 3, 4]
 
294
 
 
295
    Notes
 
296
    -----
 
297
    Edge weight attributes must be numerical.
 
298
 
 
299
    See Also
 
300
    --------
 
301
    single_source_dijkstra()
 
302
 
 
303
    """
 
304
    (length,path)=single_source_dijkstra(G,source, weight = weight)
 
305
    return path
 
306
 
 
307
 
 
308
def single_source_dijkstra_path_length(G,source, weight = 'weight'):
 
309
    """Compute shortest path length between source and all other reachable nodes for a weighted graph.
 
310
 
 
311
    Parameters
 
312
    ----------
 
313
    G : NetworkX graph
 
314
 
 
315
    source : node label
 
316
       Starting node for path
 
317
 
 
318
    weight: string, optional       
 
319
       Edge data key corresponding to the edge weight
 
320
 
 
321
    Returns
 
322
    -------
 
323
    paths : dictionary
 
324
       Dictionary of shortest paths keyed by target.
 
325
 
 
326
    Examples
 
327
    --------
 
328
    >>> G=nx.path_graph(5)
 
329
    >>> length=nx.single_source_dijkstra_path_length(G,0)
 
330
    >>> length[4]
 
331
    4
 
332
    >>> print(length)
 
333
    {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
 
334
 
 
335
    Notes
 
336
    -----
 
337
    Edge data must be numerical values for XGraph and XDiGraphs.
 
338
 
 
339
 
 
340
    See Also
 
341
    --------
 
342
    single_source_dijkstra()
 
343
 
 
344
    """
 
345
    (length,path)=single_source_dijkstra(G,source, weight = weight)
 
346
    return length
 
347
 
 
348
 
 
349
def single_source_dijkstra(G,source,target=None,cutoff=None,weight='weight'):
 
350
    """Compute shortest paths and lengths in a weighted graph G.
 
351
 
 
352
    Uses Dijkstra's algorithm for shortest paths. 
 
353
 
 
354
    Parameters
 
355
    ----------
 
356
    G : NetworkX graph
 
357
 
 
358
    source : node label
 
359
       Starting node for path
 
360
 
 
361
    target : node label, optional
 
362
       Ending node for path 
 
363
 
 
364
    cutoff : integer or float, optional
 
365
       Depth to stop the search. Only paths of length <= cutoff are returned.
 
366
 
 
367
    Returns
 
368
    -------
 
369
    distance,path : dictionaries
 
370
       Returns a tuple of two dictionaries keyed by node.
 
371
       The first dictionary stores distance from the source.
 
372
       The second stores the path from the source to that node.
 
373
 
 
374
 
 
375
    Examples
 
376
    --------
 
377
    >>> G=nx.path_graph(5)
 
378
    >>> length,path=nx.single_source_dijkstra(G,0)
 
379
    >>> print(length[4])
 
380
    4
 
381
    >>> print(length)
 
382
    {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
 
383
    >>> path[4]
 
384
    [0, 1, 2, 3, 4]
 
385
 
 
386
    Notes
 
387
    ---------
 
388
    Distances are calculated as sums of weighted edges traversed.
 
389
    Edges must hold numerical values for Graph and DiGraphs.
 
390
 
 
391
    Based on the Python cookbook recipe (119466) at 
 
392
    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/119466
 
393
 
 
394
    This algorithm is not guaranteed to work if edge weights
 
395
    are negative or are floating point numbers
 
396
    (overflows and roundoff errors can cause problems). 
 
397
    
 
398
    See Also
 
399
    --------
 
400
    single_source_dijkstra_path()
 
401
    single_source_dijkstra_path_length()
 
402
    
 
403
    """
 
404
    if source==target: return (0, [source])
 
405
    dist = {}  # dictionary of final distances
 
406
    paths = {source:[source]}  # dictionary of paths
 
407
    seen = {source:0} 
 
408
    fringe=[] # use heapq with (distance,label) tuples 
 
409
    heapq.heappush(fringe,(0,source))
 
410
    while fringe:
 
411
        (d,v)=heapq.heappop(fringe)
 
412
        if v in dist: continue # already searched this node.
 
413
        dist[v] = d
 
414
        if v == target: break
 
415
        #for ignore,w,edgedata in G.edges_iter(v,data=True):
 
416
        #is about 30% slower than the following
 
417
        if G.is_multigraph():
 
418
            edata=[]
 
419
            for w,keydata in list(G[v].items()):
 
420
                minweight=min((dd.get(weight,1)
 
421
                               for k,dd in keydata.items()))
 
422
                edata.append((w,{weight:minweight}))
 
423
        else:
 
424
            edata=iter(G[v].items())
 
425
 
 
426
 
 
427
        for w,edgedata in edata:
 
428
            vw_dist = dist[v] + edgedata.get(weight,1)
 
429
            if cutoff is not None:
 
430
                if vw_dist>cutoff: 
 
431
                    continue
 
432
            if w in dist:
 
433
                if vw_dist < dist[w]:
 
434
                    raise ValueError("Contradictory paths found: negative weights?")
 
435
            elif w not in seen or vw_dist < seen[w]:
 
436
                seen[w] = vw_dist
 
437
                heapq.heappush(fringe,(vw_dist,w))
 
438
                paths[w] = paths[v]+[w]
 
439
    return (dist,paths)
 
440
 
 
441
def dijkstra_predecessor_and_distance(G,source, weight = 'weight'):
 
442
    """Compute shorest path length and predecessors on shortest paths in weighted graphs.
 
443
 
 
444
    Parameters
 
445
    ----------
 
446
    G : NetworkX graph
 
447
 
 
448
    source : node label
 
449
       Starting node for path
 
450
 
 
451
    weight: string, optional       
 
452
       Edge data key corresponding to the edge weight
 
453
 
 
454
    Returns
 
455
    -------
 
456
    pred,distance : dictionaries
 
457
       Returns two dictionaries representing a list of predecessors 
 
458
       of a node and the distance to each node.
 
459
 
 
460
    Notes
 
461
    -----
 
462
    The list of predecessors contains more than one element only when
 
463
    there are more than one shortest paths to the key node.
 
464
    """
 
465
    push=heapq.heappush
 
466
    pop=heapq.heappop
 
467
    dist = {}  # dictionary of final distances
 
468
    pred = {source:[]}  # dictionary of predecessors
 
469
    seen = {source:0} 
 
470
    fringe=[] # use heapq with (distance,label) tuples 
 
471
    push(fringe,(0,source))
 
472
    while fringe:
 
473
        (d,v)=pop(fringe)
 
474
        if v in dist: continue # already searched this node.
 
475
        dist[v] = d
 
476
        if G.is_multigraph():
 
477
            edata=[]
 
478
            for w,keydata in G[v].items():
 
479
                minweight=min((dd.get(weight,1)
 
480
                               for k,dd in keydata.items()))
 
481
                edata.append((w,{weight:minweight}))
 
482
        else:
 
483
            edata=iter(G[v].items())
 
484
        for w,edgedata in edata:
 
485
            vw_dist = dist[v] + edgedata.get(weight,1)
 
486
            if w in dist:
 
487
                if vw_dist < dist[w]:
 
488
                    raise ValueError("Contradictory paths found: negative weights?")
 
489
            elif w not in seen or vw_dist < seen[w]:
 
490
                seen[w] = vw_dist
 
491
                push(fringe,(vw_dist,w))
 
492
                pred[w] = [v]
 
493
            elif vw_dist==seen[w]:
 
494
                pred[w].append(v)
 
495
    return (pred,dist)
 
496
 
 
497
def all_pairs_dijkstra_path_length(G, weight = 'weight'):
 
498
    """ Compute shortest path lengths between all nodes in a weighted graph.
 
499
 
 
500
    Parameters
 
501
    ----------
 
502
    G : NetworkX graph
 
503
 
 
504
    weight: string, optional       
 
505
       Edge data key corresponding to the edge weight
 
506
 
 
507
    Returns
 
508
    -------
 
509
    distance : dictionary
 
510
       Dictionary, keyed by source and target, of shortest path lengths.
 
511
 
 
512
    Examples
 
513
    --------
 
514
    >>> G=nx.path_graph(5)
 
515
    >>> length=nx.all_pairs_dijkstra_path_length(G)
 
516
    >>> print(length[1][4])
 
517
    3
 
518
    >>> length[1]
 
519
    {0: 1, 1: 0, 2: 1, 3: 2, 4: 3}
 
520
 
 
521
    Notes
 
522
    -----
 
523
    The dictionary returned only has keys for reachable node pairs.
 
524
    """
 
525
    paths={}
 
526
    for n in G:
 
527
        paths[n]=single_source_dijkstra_path_length(G,n, weight = weight)
 
528
    return paths        
 
529
 
 
530
def all_pairs_dijkstra_path(G, weight = 'weight'):
 
531
    """ Compute shortest paths between all nodes in a weighted graph.
 
532
 
 
533
    Parameters
 
534
    ----------
 
535
    G : NetworkX graph
 
536
 
 
537
    weight: string, optional       
 
538
       Edge data key corresponding to the edge weight
 
539
 
 
540
    Returns
 
541
    -------
 
542
    distance : dictionary
 
543
       Dictionary, keyed by source and target, of shortest paths.
 
544
 
 
545
    Examples
 
546
    --------
 
547
    >>> G=nx.path_graph(5)
 
548
    >>> path=nx.all_pairs_dijkstra_path(G)
 
549
    >>> print(path[0][4])
 
550
    [0, 1, 2, 3, 4]
 
551
 
 
552
    See Also
 
553
    --------
 
554
    floyd_warshall()
 
555
 
 
556
    """
 
557
    paths={}
 
558
    for n in G:
 
559
        paths[n]=single_source_dijkstra_path(G,n, weight = weight)
 
560
    return paths        
 
561
 
 
562
def bellman_ford(G, source, weight = 'weight'):
 
563
    """Compute shortest path lengths and predecessors on shortest paths 
 
564
    in weighted graphs.
 
565
 
 
566
    The algorithm has a running time of O(mn) where n is the number of nodes 
 
567
    and n is the number of edges.
 
568
 
 
569
    Parameters
 
570
    ----------
 
571
    G : NetworkX graph
 
572
       The algorithm works for all types of graphs, including directed
 
573
       graphs and multigraphs.
 
574
 
 
575
    source: node label
 
576
       Starting node for path
 
577
 
 
578
    weight: string, optional       
 
579
       Edge data key corresponding to the edge weight
 
580
 
 
581
    Returns
 
582
    -------
 
583
    pred,dist : dictionaries
 
584
       Returns two dictionaries representing a list of predecessors 
 
585
       of a node and the distance from the source to each node. The
 
586
       dictionaries are keyed by target node label.
 
587
 
 
588
    Raises
 
589
    ------
 
590
    NetworkXError
 
591
       If the (di)graph contains a negative cost (di)cycle, the
 
592
       algorithm raises an exception to indicate the presence of the
 
593
       negative cost (di)cycle.
 
594
 
 
595
    Examples
 
596
    --------
 
597
    >>> import networkx as nx
 
598
    >>> G = nx.path_graph(5, create_using = nx.DiGraph())
 
599
    >>> pred, dist = nx.bellman_ford(G, 0)
 
600
    >>> pred
 
601
    {0: None, 1: 0, 2: 1, 3: 2, 4: 3}
 
602
    >>> dist
 
603
    {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
 
604
 
 
605
    >>> from nose.tools import assert_raises
 
606
    >>> G = nx.cycle_graph(5)
 
607
    >>> G[1][2]['weight'] = -7
 
608
    >>> assert_raises(nx.NetworkXError, nx.bellman_ford, G, 0)
 
609
   
 
610
    Notes
 
611
    -----
 
612
    The dictionaries returned only have keys for nodes reachable from
 
613
    the source.
 
614
 
 
615
    In the case where the (di)graph is not connected, if a component
 
616
    not containing the source contains a negative cost (di)cycle, it
 
617
    will not be detected.
 
618
 
 
619
    """
 
620
 
 
621
    if not G.is_directed():
 
622
        directed = False
 
623
    else:
 
624
        directed = True
 
625
 
 
626
    dist = {source: 0}
 
627
    pred = {source: None}
 
628
 
 
629
    if G.number_of_nodes() == 1:
 
630
       return pred, dist
 
631
    
 
632
    def process_edge(u, v, weight):
 
633
        # Just a helper function for the main algorithm below.
 
634
        if dist.get(u) is not None:
 
635
            if dist.get(v) is None or dist[v] > dist[u] + weight:
 
636
                dist[v] = dist[u] + weight
 
637
                pred[v] = u
 
638
                return False
 
639
        return True
 
640
 
 
641
    for i in range(G.number_of_nodes()):
 
642
        feasible = True
 
643
        for u, v in G.edges():
 
644
            if G.is_multigraph():
 
645
                edata = min([eattr.get(weight, 1)
 
646
                             for eattr in G[u][v].values()])
 
647
            else:
 
648
                edata = G[u][v].get(weight, 1)
 
649
            if not process_edge(u, v, edata):
 
650
                feasible = False
 
651
            if not directed:
 
652
                if not (v, u) in G.edges():
 
653
                    if not process_edge(v, u, edata):
 
654
                        feasible = False
 
655
        if feasible:
 
656
            break
 
657
 
 
658
    if i + 1 == G.number_of_nodes():
 
659
        raise nx.NetworkXError("Negative cost cycle detected.")
 
660
    return pred, dist
 
661