gonum.org/v1/gonum@v0.14.0/graph/path/shortest.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  	"math"
     9  
    10  	"golang.org/x/exp/rand"
    11  
    12  	"gonum.org/v1/gonum/floats/scalar"
    13  	"gonum.org/v1/gonum/graph"
    14  	"gonum.org/v1/gonum/graph/internal/ordered"
    15  	"gonum.org/v1/gonum/graph/internal/set"
    16  	"gonum.org/v1/gonum/mat"
    17  )
    18  
    19  // Shortest is a shortest-path tree created by the BellmanFordFrom, DijkstraFrom
    20  // or AStar single-source shortest path functions.
    21  type Shortest struct {
    22  	// from holds the source node given to
    23  	// the function that returned the
    24  	// Shortest value.
    25  	from graph.Node
    26  
    27  	// nodes hold the nodes of the analysed
    28  	// graph.
    29  	nodes []graph.Node
    30  	// indexOf contains a mapping between
    31  	// the id-dense representation of the
    32  	// graph and the potentially id-sparse
    33  	// nodes held in nodes.
    34  	indexOf map[int64]int
    35  
    36  	// dist and next represent the shortest
    37  	// paths between nodes.
    38  	//
    39  	// Indices into dist and next are
    40  	// mapped through indexOf.
    41  	//
    42  	// dist contains the distances
    43  	// from the from node for each
    44  	// node in the graph.
    45  	dist []float64
    46  	// next contains the shortest-path
    47  	// tree of the graph. The index is a
    48  	// linear mapping of to-dense-id.
    49  	next []int
    50  
    51  	// hasNegativeCycle indicates
    52  	// whether the Shortest includes
    53  	// a negative cycle. This should
    54  	// be set by the function that
    55  	// returned the Shortest value.
    56  	hasNegativeCycle bool
    57  
    58  	// negCosts holds negative costs
    59  	// between pairs of nodes to report
    60  	// negative cycles.
    61  	// negCosts must be initialised by
    62  	// routines that can handle negative
    63  	// edge weights.
    64  	negCosts map[negEdge]float64
    65  }
    66  
    67  // newShortestFrom returns a shortest path tree for paths from u
    68  // initialised with the given nodes. The nodes held by the returned
    69  // Shortest may be lazily added.
    70  func newShortestFrom(u graph.Node, nodes []graph.Node) Shortest {
    71  	indexOf := make(map[int64]int, len(nodes))
    72  	uid := u.ID()
    73  	for i, n := range nodes {
    74  		indexOf[n.ID()] = i
    75  		if n.ID() == uid {
    76  			u = n
    77  		}
    78  	}
    79  
    80  	p := Shortest{
    81  		from: u,
    82  
    83  		nodes:   nodes,
    84  		indexOf: indexOf,
    85  
    86  		dist: make([]float64, len(nodes)),
    87  		next: make([]int, len(nodes)),
    88  	}
    89  	for i := range nodes {
    90  		p.dist[i] = math.Inf(1)
    91  		p.next[i] = -1
    92  	}
    93  	p.dist[indexOf[uid]] = 0
    94  
    95  	return p
    96  }
    97  
    98  // add adds a node to the Shortest, initialising its stored index and returning, and
    99  // setting the distance and position as unconnected. add will panic if the node is
   100  // already present.
   101  func (p *Shortest) add(u graph.Node) int {
   102  	uid := u.ID()
   103  	if _, exists := p.indexOf[uid]; exists {
   104  		panic("shortest: adding existing node")
   105  	}
   106  	idx := len(p.nodes)
   107  	p.indexOf[uid] = idx
   108  	p.nodes = append(p.nodes, u)
   109  	p.dist = append(p.dist, math.Inf(1))
   110  	p.next = append(p.next, -1)
   111  	return idx
   112  }
   113  
   114  // set sets the weight of the path from the node in p.nodes indexed by mid to the node
   115  // indexed by to.
   116  func (p Shortest) set(to int, weight float64, mid int) {
   117  	p.dist[to] = weight
   118  	p.next[to] = mid
   119  	if weight < 0 {
   120  		e := negEdge{from: mid, to: to}
   121  		c, ok := p.negCosts[e]
   122  		if !ok {
   123  			p.negCosts[e] = weight
   124  		} else if weight < c {
   125  			// The only ways that we can have a new weight that is
   126  			// lower than the previous weight is if either the edge
   127  			// has already been traversed in a negative cycle, or
   128  			// the edge is reachable from a negative cycle.
   129  			// Either way the reported path is returned with a
   130  			// negative infinite path weight.
   131  			p.negCosts[e] = math.Inf(-1)
   132  		}
   133  	}
   134  }
   135  
   136  // From returns the starting node of the paths held by the Shortest.
   137  func (p Shortest) From() graph.Node { return p.from }
   138  
   139  // WeightTo returns the weight of the minimum path to v. If the path to v includes
   140  // a negative cycle, the returned weight will not reflect the true path weight.
   141  func (p Shortest) WeightTo(vid int64) float64 {
   142  	to, toOK := p.indexOf[vid]
   143  	if !toOK {
   144  		return math.Inf(1)
   145  	}
   146  	return p.dist[to]
   147  }
   148  
   149  // To returns a shortest path to v and the weight of the path. If the path
   150  // to v includes a negative cycle, one pass through the cycle will be included
   151  // in path, but any path leading into the negative cycle will be lost, and
   152  // weight will be returned as -Inf.
   153  func (p Shortest) To(vid int64) (path []graph.Node, weight float64) {
   154  	to, toOK := p.indexOf[vid]
   155  	if !toOK || math.IsInf(p.dist[to], 1) {
   156  		return nil, math.Inf(1)
   157  	}
   158  	from := p.indexOf[p.from.ID()]
   159  	path = []graph.Node{p.nodes[to]}
   160  	weight = math.Inf(1)
   161  	if p.hasNegativeCycle {
   162  		seen := make(set.Ints)
   163  		seen.Add(from)
   164  		for to != from {
   165  			next := p.next[to]
   166  			if math.IsInf(p.negCosts[negEdge{from: next, to: to}], -1) {
   167  				weight = math.Inf(-1)
   168  			}
   169  			if seen.Has(to) {
   170  				break
   171  			}
   172  			seen.Add(to)
   173  			path = append(path, p.nodes[next])
   174  			to = next
   175  		}
   176  	} else {
   177  		n := len(p.nodes)
   178  		for to != from {
   179  			to = p.next[to]
   180  			path = append(path, p.nodes[to])
   181  			if n < 0 {
   182  				panic("path: unexpected negative cycle")
   183  			}
   184  			n--
   185  		}
   186  	}
   187  	ordered.Reverse(path)
   188  	return path, math.Min(weight, p.dist[p.indexOf[vid]])
   189  }
   190  
   191  // ShortestAlts is a shortest-path tree created by the BellmanFordAllFrom or DijkstraAllFrom
   192  // single-source shortest path functions.
   193  type ShortestAlts struct {
   194  	// from holds the source node given to
   195  	// the function that returned the
   196  	// ShortestAlts value.
   197  	from graph.Node
   198  
   199  	// nodes hold the nodes of the analysed
   200  	// graph.
   201  	nodes []graph.Node
   202  	// indexOf contains a mapping between
   203  	// the id-dense representation of the
   204  	// graph and the potentially id-sparse
   205  	// nodes held in nodes.
   206  	indexOf map[int64]int
   207  
   208  	// dist and next represent the shortest
   209  	// paths between nodes.
   210  	//
   211  	// Indices into dist and next are
   212  	// mapped through indexOf.
   213  	//
   214  	// dist contains the distances
   215  	// from the from node for each
   216  	// node in the graph.
   217  	dist []float64
   218  	// next contains the shortest-path
   219  	// tree of the graph. The index is a
   220  	// linear mapping of to-dense-id.
   221  	next [][]int
   222  
   223  	// hasNegativeCycle indicates
   224  	// whether the ShortestAlts includes
   225  	// a negative cycle. This should
   226  	// be set by the function that
   227  	// returned the ShortestAlts value.
   228  	hasNegativeCycle bool
   229  
   230  	// negCosts holds negative costs
   231  	// between pairs of nodes to report
   232  	// negative cycles.
   233  	// negCosts must be initialised by
   234  	// routines that can handle negative
   235  	// edge weights.
   236  	negCosts map[negEdge]float64
   237  }
   238  
   239  // newShortestAltsFrom returns a shortest path tree for all paths from u
   240  // initialised with the given nodes. The nodes held by the returned
   241  // Shortest may be lazily added.
   242  func newShortestAltsFrom(u graph.Node, nodes []graph.Node) ShortestAlts {
   243  	indexOf := make(map[int64]int, len(nodes))
   244  	uid := u.ID()
   245  	for i, n := range nodes {
   246  		indexOf[n.ID()] = i
   247  		if n.ID() == uid {
   248  			u = n
   249  		}
   250  	}
   251  
   252  	p := ShortestAlts{
   253  		from: u,
   254  
   255  		nodes:   nodes,
   256  		indexOf: indexOf,
   257  
   258  		dist: make([]float64, len(nodes)),
   259  		next: make([][]int, len(nodes)),
   260  	}
   261  	for i := range nodes {
   262  		p.dist[i] = math.Inf(1)
   263  		p.next[i] = nil
   264  	}
   265  	p.dist[indexOf[uid]] = 0
   266  
   267  	return p
   268  }
   269  
   270  // add adds a node to the ShortestAlts, initialising its stored index and returning, and
   271  // setting the distance and position as unconnected. add will panic if the node is
   272  // already present.
   273  func (p *ShortestAlts) add(u graph.Node) int {
   274  	uid := u.ID()
   275  	if _, exists := p.indexOf[uid]; exists {
   276  		panic("shortest: adding existing node")
   277  	}
   278  	idx := len(p.nodes)
   279  	p.indexOf[uid] = idx
   280  	p.nodes = append(p.nodes, u)
   281  	p.dist = append(p.dist, math.Inf(1))
   282  	p.next = append(p.next, nil)
   283  	return idx
   284  }
   285  
   286  // set sets the weight of the path from the node in p.nodes indexed by mid to the node
   287  // indexed by to.
   288  func (p ShortestAlts) set(to int, weight float64, mid int) {
   289  	p.dist[to] = weight
   290  	p.next[to] = []int{mid}
   291  	if weight < 0 {
   292  		e := negEdge{from: mid, to: to}
   293  		c, ok := p.negCosts[e]
   294  		if !ok {
   295  			p.negCosts[e] = weight
   296  		} else if weight < c {
   297  			// The only ways that we can have a new weight that is
   298  			// lower than the previous weight is if either the edge
   299  			// has already been traversed in a negative cycle, or
   300  			// the edge is reachable from a negative cycle.
   301  			// Either way the reported path is returned with a
   302  			// negative infinite path weight.
   303  			p.negCosts[e] = math.Inf(-1)
   304  		}
   305  	}
   306  }
   307  
   308  // addPath adds a new path from the node in p.nodes indexed by mid to the node indexed
   309  // by to. The weight of the path is expected to be the same as already existing paths
   310  // between these nodes, but no check is made for this.
   311  func (p ShortestAlts) addPath(to, mid int) {
   312  	// These are likely to be rare, so just loop over collisions.
   313  	for _, v := range p.next[to] {
   314  		if mid == v {
   315  			return
   316  		}
   317  	}
   318  	p.next[to] = append(p.next[to], mid)
   319  }
   320  
   321  // From returns the starting node of the paths held by the ShortestAlts.
   322  func (p ShortestAlts) From() graph.Node { return p.from }
   323  
   324  // WeightTo returns the weight of the minimum path to v. If the path to v includes
   325  // a negative cycle, the returned weight will not reflect the true path weight.
   326  func (p ShortestAlts) WeightTo(vid int64) float64 {
   327  	to, toOK := p.indexOf[vid]
   328  	if !toOK {
   329  		return math.Inf(1)
   330  	}
   331  	return p.dist[to]
   332  }
   333  
   334  // To returns a shortest path to v and the weight of the path. If more than
   335  // one shortest path exists between u and v, a randomly chosen path will be
   336  // returned and unique is returned false. If a cycle with zero weight exists
   337  // in the path, it will not be included, but unique will be returned false.
   338  // If the path to v includes a negative cycle, one pass through the cycle will
   339  // be included in path, but any path leading into the negative cycle will be
   340  // lost, and weight will be returned as -Inf.
   341  func (p ShortestAlts) To(vid int64) (path []graph.Node, weight float64, unique bool) {
   342  	to, toOK := p.indexOf[vid]
   343  	if !toOK || math.IsInf(p.dist[to], 1) {
   344  		return nil, math.Inf(1), false
   345  	}
   346  	from := p.indexOf[p.from.ID()]
   347  	unique = true
   348  	path = []graph.Node{p.nodes[to]}
   349  	if p.hasNegativeCycle {
   350  		weight = math.Inf(1)
   351  		seen := make(set.Ints)
   352  		seen.Add(from)
   353  		for to != from {
   354  			c := p.next[to]
   355  			var next int
   356  			if len(c) != 1 {
   357  				unique = false
   358  				next = c[rand.Intn(len(c))]
   359  			} else {
   360  				next = c[0]
   361  			}
   362  			if math.IsInf(p.negCosts[negEdge{from: next, to: to}], -1) {
   363  				weight = math.Inf(-1)
   364  				unique = false
   365  			}
   366  			if seen.Has(to) {
   367  				break
   368  			}
   369  			seen.Add(to)
   370  			path = append(path, p.nodes[next])
   371  			to = next
   372  		}
   373  		weight = math.Min(weight, p.dist[p.indexOf[vid]])
   374  	} else {
   375  		seen := make([]int, len(p.nodes))
   376  		for i := range seen {
   377  			seen[i] = -1
   378  		}
   379  		seen[to] = 0
   380  
   381  		var next int
   382  		for from != to {
   383  			c := p.next[to]
   384  			if len(c) != 1 {
   385  				unique = false
   386  				next = c[rand.Intn(len(c))]
   387  			} else {
   388  				next = c[0]
   389  			}
   390  			if seen[next] >= 0 {
   391  				path = path[:seen[next]]
   392  			}
   393  			seen[next] = len(path)
   394  			path = append(path, p.nodes[next])
   395  			to = next
   396  		}
   397  		weight = p.dist[p.indexOf[vid]]
   398  	}
   399  
   400  	ordered.Reverse(path)
   401  	return path, weight, unique
   402  }
   403  
   404  // AllTo returns all shortest paths to v and the weight of the paths. Paths
   405  // containing zero-weight cycles are not returned. If a negative cycle exists between
   406  // u and v, paths is returned nil and weight is returned as -Inf.
   407  func (p ShortestAlts) AllTo(vid int64) (paths [][]graph.Node, weight float64) {
   408  	from := p.indexOf[p.from.ID()]
   409  	to, toOK := p.indexOf[vid]
   410  	if !toOK || len(p.next[to]) == 0 {
   411  		if p.from.ID() == vid {
   412  			return [][]graph.Node{{p.nodes[from]}}, 0
   413  		}
   414  		return nil, math.Inf(1)
   415  	}
   416  
   417  	_, weight, unique := p.To(vid)
   418  	if math.IsInf(weight, -1) && !unique {
   419  		return nil, math.Inf(-1)
   420  	}
   421  
   422  	seen := make([]bool, len(p.nodes))
   423  	p.allTo(from, to, seen, []graph.Node{p.nodes[to]}, func(path []graph.Node) {
   424  		paths = append(paths, append([]graph.Node(nil), path...))
   425  	})
   426  	weight = p.dist[to]
   427  
   428  	return paths, weight
   429  }
   430  
   431  // AllToFunc calls fn on all shortest paths to v. Paths containing zero-weight
   432  // cycles are not considered. If a negative cycle exists between u and v, no
   433  // path is considered. The fn closure must not retain the path parameter.
   434  func (p ShortestAlts) AllToFunc(vid int64, fn func(path []graph.Node)) {
   435  	from := p.indexOf[p.from.ID()]
   436  	to, toOK := p.indexOf[vid]
   437  	if !toOK || len(p.next[to]) == 0 {
   438  		if p.from.ID() == vid {
   439  			fn([]graph.Node{p.nodes[from]})
   440  		}
   441  		return
   442  	}
   443  
   444  	_, weight, unique := p.To(vid)
   445  	if math.IsInf(weight, -1) && !unique {
   446  		return
   447  	}
   448  
   449  	seen := make([]bool, len(p.nodes))
   450  	p.allTo(from, to, seen, []graph.Node{p.nodes[to]}, fn)
   451  }
   452  
   453  // allTo recursively constructs a slice of paths extending from the node
   454  // indexed into p.nodes by from to the node indexed by to. len(seen) must match
   455  // the number of nodes held by the receiver. The path parameter is the current
   456  // working path and the results passed to fn.
   457  func (p ShortestAlts) allTo(from, to int, seen []bool, path []graph.Node, fn func(path []graph.Node)) {
   458  	seen[to] = true
   459  	if from == to {
   460  		if path == nil {
   461  			return
   462  		}
   463  		ordered.Reverse(path)
   464  		fn(path)
   465  		ordered.Reverse(path)
   466  		return
   467  	}
   468  	first := true
   469  	var seenWork []bool
   470  	for _, to := range p.next[to] {
   471  		if seen[to] {
   472  			continue
   473  		}
   474  		if first {
   475  			p := make([]graph.Node, len(path), len(path)+1)
   476  			copy(p, path)
   477  			path = p
   478  			seenWork = make([]bool, len(seen))
   479  			first = false
   480  		}
   481  		copy(seenWork, seen)
   482  		p.allTo(from, to, seenWork, append(path, p.nodes[to]), fn)
   483  	}
   484  }
   485  
   486  // negEdge is a key into the negative costs map used by Shortest and ShortestAlts.
   487  type negEdge struct{ from, to int }
   488  
   489  // AllShortest is a shortest-path tree created by the DijkstraAllPaths, FloydWarshall
   490  // or JohnsonAllPaths all-pairs shortest paths functions.
   491  type AllShortest struct {
   492  	// nodes hold the nodes of the analysed
   493  	// graph.
   494  	nodes []graph.Node
   495  	// indexOf contains a mapping between
   496  	// the id-dense representation of the
   497  	// graph and the potentially id-sparse
   498  	// nodes held in nodes.
   499  	indexOf map[int64]int
   500  
   501  	// dist, next and forward represent
   502  	// the shortest paths between nodes.
   503  	//
   504  	// Indices into dist and next are
   505  	// mapped through indexOf.
   506  	//
   507  	// dist contains the pairwise
   508  	// distances between nodes.
   509  	//
   510  	// Internally, edges on negative
   511  	// cycles are given a special NaN
   512  	// weight, NaN(0xdefaced).
   513  	// This is returned to the user as
   514  	// -Inf. This approach allows -Inf
   515  	// weight edges on simple paths to be
   516  	// distinguished from -Inf weight
   517  	// paths that contain negative cycles.
   518  	// The distinction is visible to the
   519  	// user through whether then path
   520  	// returned with a -Inf weight is
   521  	// nil or contains a set of nodes.
   522  	dist *mat.Dense
   523  	// next contains the shortest-path
   524  	// tree of the graph. The first index
   525  	// is a linear mapping of from-dense-id
   526  	// and to-dense-id, to-major with a
   527  	// stride equal to len(nodes); the
   528  	// slice indexed to is the list of
   529  	// intermediates leading from the 'from'
   530  	// node to the 'to' node represented
   531  	// by dense id.
   532  	// The interpretation of next is
   533  	// dependent on the state of forward.
   534  	next [][]int
   535  	// forward indicates the direction of
   536  	// path reconstruction. Forward
   537  	// reconstruction is used for Floyd-
   538  	// Warshall and reverse is used for
   539  	// Dijkstra.
   540  	forward bool
   541  }
   542  
   543  var (
   544  	// defaced is NaN(0xdefaced) used as a marker for -Inf weight edges
   545  	// within paths containing negative cycles. Routines marking these
   546  	// edges should use this value.
   547  	defaced = scalar.NaNWith(0xdefaced)
   548  	// defacedBits is the bit pattern we look for in AllShortest to
   549  	// identify the edges.
   550  	defacedBits = math.Float64bits(defaced)
   551  )
   552  
   553  // newAllShortest returns an all-pairs shortest path forest for paths with the
   554  // given nodes. The forward flag indicates whether the path reconstruction is
   555  // performed in the forward (Floyd-Warshall) or reverse (Dijkstra/Johnson's) order.
   556  func newAllShortest(nodes []graph.Node, forward bool) AllShortest {
   557  	if len(nodes) == 0 {
   558  		return AllShortest{}
   559  	}
   560  	indexOf := make(map[int64]int, len(nodes))
   561  	for i, n := range nodes {
   562  		indexOf[n.ID()] = i
   563  	}
   564  	dist := make([]float64, len(nodes)*len(nodes))
   565  	for i := range dist {
   566  		dist[i] = math.Inf(1)
   567  	}
   568  	return AllShortest{
   569  		nodes:   nodes,
   570  		indexOf: indexOf,
   571  
   572  		dist:    mat.NewDense(len(nodes), len(nodes), dist),
   573  		next:    make([][]int, len(nodes)*len(nodes)),
   574  		forward: forward,
   575  	}
   576  }
   577  
   578  // at returns a slice of node indexes into p.nodes for nodes that are mid points
   579  // between nodes indexed by from and to.
   580  func (p AllShortest) at(from, to int) (mid []int) {
   581  	return p.next[from+to*len(p.nodes)]
   582  }
   583  
   584  // set sets the weights of paths between node indexes into p.nodes for from and to
   585  // passing through the nodes indexed by mid.
   586  func (p AllShortest) set(from, to int, weight float64, mid ...int) {
   587  	p.dist.Set(from, to, weight)
   588  	p.next[from+to*len(p.nodes)] = append(p.next[from+to*len(p.nodes)][:0], mid...)
   589  }
   590  
   591  // add adds paths between node indexed in p.nodes by from and to passing through
   592  // the nodes indexed by mid.
   593  func (p AllShortest) add(from, to int, mid ...int) {
   594  loop: // These are likely to be rare, so just loop over collisions.
   595  	for _, k := range mid {
   596  		for _, v := range p.next[from+to*len(p.nodes)] {
   597  			if k == v {
   598  				continue loop
   599  			}
   600  		}
   601  		p.next[from+to*len(p.nodes)] = append(p.next[from+to*len(p.nodes)], k)
   602  	}
   603  }
   604  
   605  // Weight returns the weight of the minimum path between u and v.
   606  func (p AllShortest) Weight(uid, vid int64) float64 {
   607  	from, fromOK := p.indexOf[uid]
   608  	to, toOK := p.indexOf[vid]
   609  	if !fromOK || !toOK {
   610  		return math.Inf(1)
   611  	}
   612  	w := p.dist.At(from, to)
   613  	if math.Float64bits(w) == defacedBits {
   614  		return math.Inf(-1)
   615  	}
   616  	return w
   617  }
   618  
   619  // Between returns a shortest path from u to v and the weight of the path. If more than
   620  // one shortest path exists between u and v, a randomly chosen path will be returned and
   621  // unique is returned false. If a cycle with zero weight exists in the path, it will not
   622  // be included, but unique will be returned false. If a negative cycle exists on the path
   623  // from u to v, path will be returned nil, weight will be -Inf and unique will be false.
   624  func (p AllShortest) Between(uid, vid int64) (path []graph.Node, weight float64, unique bool) {
   625  	from, fromOK := p.indexOf[uid]
   626  	to, toOK := p.indexOf[vid]
   627  	if !fromOK || !toOK || len(p.at(from, to)) == 0 {
   628  		if uid == vid {
   629  			if !fromOK {
   630  				return []graph.Node{node(uid)}, 0, true
   631  			}
   632  			return []graph.Node{p.nodes[from]}, 0, true
   633  		}
   634  		return nil, math.Inf(1), false
   635  	}
   636  
   637  	weight = p.dist.At(from, to)
   638  	if math.Float64bits(weight) == defacedBits {
   639  		return nil, math.Inf(-1), false
   640  	}
   641  
   642  	seen := make([]int, len(p.nodes))
   643  	for i := range seen {
   644  		seen[i] = -1
   645  	}
   646  	var n graph.Node
   647  	if p.forward {
   648  		n = p.nodes[from]
   649  		seen[from] = 0
   650  	} else {
   651  		n = p.nodes[to]
   652  		seen[to] = 0
   653  	}
   654  
   655  	path = []graph.Node{n}
   656  	unique = true
   657  
   658  	var next int
   659  	for from != to {
   660  		c := p.at(from, to)
   661  		if len(c) != 1 {
   662  			unique = false
   663  			next = c[rand.Intn(len(c))]
   664  		} else {
   665  			next = c[0]
   666  		}
   667  		if seen[next] >= 0 {
   668  			path = path[:seen[next]]
   669  		}
   670  		seen[next] = len(path)
   671  		path = append(path, p.nodes[next])
   672  		if p.forward {
   673  			from = next
   674  		} else {
   675  			to = next
   676  		}
   677  	}
   678  	if !p.forward {
   679  		ordered.Reverse(path)
   680  	}
   681  
   682  	return path, weight, unique
   683  }
   684  
   685  // AllBetween returns all shortest paths from u to v and the weight of the paths. Paths
   686  // containing zero-weight cycles are not returned. If a negative cycle exists between
   687  // u and v, paths is returned nil and weight is returned as -Inf.
   688  func (p AllShortest) AllBetween(uid, vid int64) (paths [][]graph.Node, weight float64) {
   689  	from, fromOK := p.indexOf[uid]
   690  	to, toOK := p.indexOf[vid]
   691  	if !fromOK || !toOK || len(p.at(from, to)) == 0 {
   692  		if uid == vid {
   693  			if !fromOK {
   694  				return [][]graph.Node{{node(uid)}}, 0
   695  			}
   696  			return [][]graph.Node{{p.nodes[from]}}, 0
   697  		}
   698  		return nil, math.Inf(1)
   699  	}
   700  
   701  	weight = p.dist.At(from, to)
   702  	if math.Float64bits(weight) == defacedBits {
   703  		return nil, math.Inf(-1)
   704  	}
   705  
   706  	var n graph.Node
   707  	if p.forward {
   708  		n = p.nodes[from]
   709  	} else {
   710  		n = p.nodes[to]
   711  	}
   712  	seen := make([]bool, len(p.nodes))
   713  	p.allBetween(from, to, seen, []graph.Node{n}, func(path []graph.Node) {
   714  		paths = append(paths, append([]graph.Node(nil), path...))
   715  	})
   716  
   717  	return paths, weight
   718  }
   719  
   720  // AllBetweenFunc calls fn on all shortest paths from u to v. Paths containing
   721  // zero-weight cycles are not considered. If a negative cycle exists between u
   722  // and v, no path is considered. The fn closure must not retain the path
   723  // parameter.
   724  func (p AllShortest) AllBetweenFunc(uid, vid int64, fn func(path []graph.Node)) {
   725  	from, fromOK := p.indexOf[uid]
   726  	to, toOK := p.indexOf[vid]
   727  	if !fromOK || !toOK || len(p.at(from, to)) == 0 {
   728  		if uid == vid {
   729  			if !fromOK {
   730  				fn([]graph.Node{node(uid)})
   731  				return
   732  			}
   733  			fn([]graph.Node{p.nodes[from]})
   734  			return
   735  		}
   736  		return
   737  	}
   738  
   739  	if math.Float64bits(p.dist.At(from, to)) == defacedBits {
   740  		return
   741  	}
   742  
   743  	var n graph.Node
   744  	if p.forward {
   745  		n = p.nodes[from]
   746  	} else {
   747  		n = p.nodes[to]
   748  	}
   749  	seen := make([]bool, len(p.nodes))
   750  	p.allBetween(from, to, seen, []graph.Node{n}, fn)
   751  }
   752  
   753  // allBetween recursively constructs a set of paths extending from the node
   754  // indexed into p.nodes by from to the node indexed by to. len(seen) must match
   755  // the number of nodes held by the receiver. The path parameter is the current
   756  // working path and the results passed to fn.
   757  func (p AllShortest) allBetween(from, to int, seen []bool, path []graph.Node, fn func([]graph.Node)) {
   758  	if p.forward {
   759  		seen[from] = true
   760  	} else {
   761  		seen[to] = true
   762  	}
   763  	if from == to {
   764  		if path == nil {
   765  			return
   766  		}
   767  		if !p.forward {
   768  			ordered.Reverse(path)
   769  		}
   770  		fn(path)
   771  		if !p.forward {
   772  			ordered.Reverse(path)
   773  		}
   774  		return
   775  	}
   776  	first := true
   777  	var seenWork []bool
   778  	for _, n := range p.at(from, to) {
   779  		if seen[n] {
   780  			continue
   781  		}
   782  		if first {
   783  			p := make([]graph.Node, len(path), len(path)+1)
   784  			copy(p, path)
   785  			path = p
   786  			seenWork = make([]bool, len(seen))
   787  			first = false
   788  		}
   789  		if p.forward {
   790  			from = n
   791  		} else {
   792  			to = n
   793  		}
   794  		copy(seenWork, seen)
   795  		p.allBetween(from, to, seenWork, append(path, p.nodes[n]), fn)
   796  	}
   797  }
   798  
   799  type node int64
   800  
   801  func (n node) ID() int64 { return int64(n) }