github.com/gopherd/gonum@v0.0.4/graph/path/bellman_ford_moore.go (about)

     1  // Copyright ©2015 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package path
     6  
     7  import (
     8  	"github.com/gopherd/gonum/graph"
     9  	"github.com/gopherd/gonum/graph/internal/linear"
    10  	"github.com/gopherd/gonum/graph/traverse"
    11  )
    12  
    13  // BellmanFordFrom returns a shortest-path tree for a shortest path from u to all nodes in
    14  // the graph g, or false indicating that a negative cycle exists in the graph. If the graph
    15  // does not implement Weighted, UniformCost is used.
    16  //
    17  // If g is a graph.Graph, all nodes of the graph will be stored in the shortest-path
    18  // tree, otherwise only nodes reachable from u will be stored.
    19  //
    20  // The time complexity of BellmanFordFrom is O(|V|.|E|).
    21  func BellmanFordFrom(u graph.Node, g traverse.Graph) (path Shortest, ok bool) {
    22  	if h, ok := g.(graph.Graph); ok {
    23  		if h.Node(u.ID()) == nil {
    24  			return Shortest{from: u}, true
    25  		}
    26  		path = newShortestFrom(u, graph.NodesOf(h.Nodes()))
    27  	} else {
    28  		if g.From(u.ID()) == graph.Empty {
    29  			return Shortest{from: u}, true
    30  		}
    31  		path = newShortestFrom(u, []graph.Node{u})
    32  	}
    33  	path.dist[path.indexOf[u.ID()]] = 0
    34  	path.negCosts = make(map[negEdge]float64)
    35  
    36  	var weight Weighting
    37  	if wg, ok := g.(Weighted); ok {
    38  		weight = wg.Weight
    39  	} else {
    40  		weight = UniformCost(g)
    41  	}
    42  
    43  	// Queue to keep track which nodes need to be relaxed.
    44  	// Only nodes whose vertex distance changed in the previous iterations
    45  	// need to be relaxed again.
    46  	queue := newBellmanFordQueue(path.indexOf)
    47  	queue.enqueue(u)
    48  
    49  	// TODO(kortschak): Consider adding further optimisations
    50  	// from http://arxiv.org/abs/1111.5414.
    51  	var loops int64
    52  	for queue.len() != 0 {
    53  		u := queue.dequeue()
    54  		uid := u.ID()
    55  		j := path.indexOf[uid]
    56  
    57  		to := g.From(uid)
    58  		for to.Next() {
    59  			v := to.Node()
    60  			vid := v.ID()
    61  			k, ok := path.indexOf[vid]
    62  			if !ok {
    63  				k = path.add(v)
    64  			}
    65  			w, ok := weight(uid, vid)
    66  			if !ok {
    67  				panic("bellman-ford: unexpected invalid weight")
    68  			}
    69  
    70  			joint := path.dist[j] + w
    71  			if joint < path.dist[k] {
    72  				path.set(k, joint, j)
    73  
    74  				if !queue.has(vid) {
    75  					queue.enqueue(v)
    76  				}
    77  			}
    78  		}
    79  
    80  		// The maximum number of edges in the relaxed subgraph is |V_r| * (|V_r|-1).
    81  		// If the queue-loop has more iterations than the maximum number of edges
    82  		// it indicates that we have a negative cycle.
    83  		maxEdges := int64(len(path.nodes)) * int64(len(path.nodes)-1)
    84  		if loops > maxEdges {
    85  			path.hasNegativeCycle = true
    86  			return path, false
    87  		}
    88  		loops++
    89  	}
    90  
    91  	return path, true
    92  }
    93  
    94  // BellmanFordAllFrom returns a shortest-path tree for shortest paths from u to all nodes in
    95  // the graph g, or false indicating that a negative cycle exists in the graph. If the graph
    96  // does not implement Weighted, UniformCost is used.
    97  //
    98  // If g is a graph.Graph, all nodes of the graph will be stored in the shortest-path
    99  // tree, otherwise only nodes reachable from u will be stored.
   100  //
   101  // The time complexity of BellmanFordAllFrom is O(|V|.|E|).
   102  func BellmanFordAllFrom(u graph.Node, g traverse.Graph) (path ShortestAlts, ok bool) {
   103  	if h, ok := g.(graph.Graph); ok {
   104  		if h.Node(u.ID()) == nil {
   105  			return ShortestAlts{from: u}, true
   106  		}
   107  		path = newShortestAltsFrom(u, graph.NodesOf(h.Nodes()))
   108  	} else {
   109  		if g.From(u.ID()) == graph.Empty {
   110  			return ShortestAlts{from: u}, true
   111  		}
   112  		path = newShortestAltsFrom(u, []graph.Node{u})
   113  	}
   114  	path.dist[path.indexOf[u.ID()]] = 0
   115  	path.negCosts = make(map[negEdge]float64)
   116  
   117  	var weight Weighting
   118  	if wg, ok := g.(Weighted); ok {
   119  		weight = wg.Weight
   120  	} else {
   121  		weight = UniformCost(g)
   122  	}
   123  
   124  	// Queue to keep track which nodes need to be relaxed.
   125  	// Only nodes whose vertex distance changed in the previous iterations
   126  	// need to be relaxed again.
   127  	queue := newBellmanFordQueue(path.indexOf)
   128  	queue.enqueue(u)
   129  
   130  	// TODO(kortschak): Consider adding further optimisations
   131  	// from http://arxiv.org/abs/1111.5414.
   132  	var loops int64
   133  	for queue.len() != 0 {
   134  		u := queue.dequeue()
   135  		uid := u.ID()
   136  		j := path.indexOf[uid]
   137  
   138  		for _, v := range graph.NodesOf(g.From(uid)) {
   139  			vid := v.ID()
   140  			k, ok := path.indexOf[vid]
   141  			if !ok {
   142  				k = path.add(v)
   143  			}
   144  			w, ok := weight(uid, vid)
   145  			if !ok {
   146  				panic("bellman-ford: unexpected invalid weight")
   147  			}
   148  
   149  			joint := path.dist[j] + w
   150  			if joint < path.dist[k] {
   151  				path.set(k, joint, j)
   152  
   153  				if !queue.has(vid) {
   154  					queue.enqueue(v)
   155  				}
   156  			} else if joint == path.dist[k] {
   157  				path.addPath(k, j)
   158  			}
   159  		}
   160  
   161  		// The maximum number of edges in the relaxed subgraph is |V_r| * (|V_r|-1).
   162  		// If the queue-loop has more iterations than the maximum number of edges
   163  		// it indicates that we have a negative cycle.
   164  		maxEdges := int64(len(path.nodes)) * int64(len(path.nodes)-1)
   165  		if loops > maxEdges {
   166  			path.hasNegativeCycle = true
   167  			return path, false
   168  		}
   169  		loops++
   170  	}
   171  
   172  	return path, true
   173  }
   174  
   175  // bellmanFordQueue is a queue for the Queue-based Bellman-Ford algorithm.
   176  type bellmanFordQueue struct {
   177  	// queue holds the nodes which need to be relaxed.
   178  	queue linear.NodeQueue
   179  
   180  	// onQueue keeps track whether a node is on the queue or not.
   181  	onQueue []bool
   182  
   183  	// indexOf contains a mapping holding the id of a node with its index in the onQueue array.
   184  	indexOf map[int64]int
   185  }
   186  
   187  // enqueue adds a node to the bellmanFordQueue.
   188  func (q *bellmanFordQueue) enqueue(n graph.Node) {
   189  	i, ok := q.indexOf[n.ID()]
   190  	switch {
   191  	case !ok:
   192  		panic("bellman-ford: unknown node")
   193  	case i < len(q.onQueue):
   194  		if q.onQueue[i] {
   195  			panic("bellman-ford: already queued")
   196  		}
   197  	case i == len(q.onQueue):
   198  		q.onQueue = append(q.onQueue, false)
   199  	case i < cap(q.onQueue):
   200  		q.onQueue = q.onQueue[:i+1]
   201  	default:
   202  		q.onQueue = append(q.onQueue, make([]bool, i-len(q.onQueue)+1)...)
   203  	}
   204  	q.onQueue[i] = true
   205  	q.queue.Enqueue(n)
   206  }
   207  
   208  // dequeue returns the first value of the bellmanFordQueue.
   209  func (q *bellmanFordQueue) dequeue() graph.Node {
   210  	n := q.queue.Dequeue()
   211  	q.onQueue[q.indexOf[n.ID()]] = false
   212  	return n
   213  }
   214  
   215  // len returns the number of nodes in the bellmanFordQueue.
   216  func (q *bellmanFordQueue) len() int { return q.queue.Len() }
   217  
   218  // has returns whether a node with the given id is in the queue.
   219  func (q bellmanFordQueue) has(id int64) bool {
   220  	idx, ok := q.indexOf[id]
   221  	if !ok || idx >= len(q.onQueue) {
   222  		return false
   223  	}
   224  	return q.onQueue[idx]
   225  }
   226  
   227  // newBellmanFordQueue creates a new bellmanFordQueue.
   228  func newBellmanFordQueue(indexOf map[int64]int) bellmanFordQueue {
   229  	return bellmanFordQueue{
   230  		onQueue: make([]bool, len(indexOf)),
   231  		indexOf: indexOf,
   232  	}
   233  }