github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/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  	"github.com/jingcheng-WU/gonum/floats/scalar"
    13  	"github.com/jingcheng-WU/gonum/graph"
    14  	"github.com/jingcheng-WU/gonum/graph/internal/ordered"
    15  	"github.com/jingcheng-WU/gonum/graph/internal/set"
    16  	"github.com/jingcheng-WU/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  	paths = p.allTo(from, to, seen, []graph.Node{p.nodes[to]}, nil)
   424  	weight = p.dist[to]
   425  
   426  	return paths, weight
   427  }
   428  
   429  // allTo recursively constructs a slice of paths extending from the node
   430  // indexed into p.nodes by from to the node indexed by to. len(seen) must match
   431  // the number of nodes held by the receiver. The path parameter is the current
   432  // working path and the results are written into paths.
   433  func (p ShortestAlts) allTo(from, to int, seen []bool, path []graph.Node, paths [][]graph.Node) [][]graph.Node {
   434  	seen[to] = true
   435  	if from == to {
   436  		if path == nil {
   437  			return paths
   438  		}
   439  		ordered.Reverse(path)
   440  		return append(paths, path)
   441  	}
   442  	first := true
   443  	for _, to := range p.next[to] {
   444  		if seen[to] {
   445  			continue
   446  		}
   447  		if first {
   448  			path = append([]graph.Node(nil), path...)
   449  			first = false
   450  		}
   451  		path = path[:len(path):len(path)]
   452  		paths = p.allTo(from, to, append([]bool(nil), seen...), append(path, p.nodes[to]), paths)
   453  	}
   454  	return paths
   455  }
   456  
   457  // negEdge is a key into the negative costs map used by Shortest and ShortestAlts.
   458  type negEdge struct{ from, to int }
   459  
   460  // AllShortest is a shortest-path tree created by the DijkstraAllPaths, FloydWarshall
   461  // or JohnsonAllPaths all-pairs shortest paths functions.
   462  type AllShortest struct {
   463  	// nodes hold the nodes of the analysed
   464  	// graph.
   465  	nodes []graph.Node
   466  	// indexOf contains a mapping between
   467  	// the id-dense representation of the
   468  	// graph and the potentially id-sparse
   469  	// nodes held in nodes.
   470  	indexOf map[int64]int
   471  
   472  	// dist, next and forward represent
   473  	// the shortest paths between nodes.
   474  	//
   475  	// Indices into dist and next are
   476  	// mapped through indexOf.
   477  	//
   478  	// dist contains the pairwise
   479  	// distances between nodes.
   480  	//
   481  	// Internally, edges on negative
   482  	// cycles are given a special NaN
   483  	// weight, NaN(0xdefaced).
   484  	// This is returned to the user as
   485  	// -Inf. This approach allows -Inf
   486  	// weight edges on simple paths to be
   487  	// distinguished from -Inf weight
   488  	// paths that contain negative cycles.
   489  	// The distinction is visible to the
   490  	// user through whether then path
   491  	// returned with a -Inf weight is
   492  	// nil or contains a set of nodes.
   493  	dist *mat.Dense
   494  	// next contains the shortest-path
   495  	// tree of the graph. The first index
   496  	// is a linear mapping of from-dense-id
   497  	// and to-dense-id, to-major with a
   498  	// stride equal to len(nodes); the
   499  	// slice indexed to is the list of
   500  	// intermediates leading from the 'from'
   501  	// node to the 'to' node represented
   502  	// by dense id.
   503  	// The interpretation of next is
   504  	// dependent on the state of forward.
   505  	next [][]int
   506  	// forward indicates the direction of
   507  	// path reconstruction. Forward
   508  	// reconstruction is used for Floyd-
   509  	// Warshall and reverse is used for
   510  	// Dijkstra.
   511  	forward bool
   512  }
   513  
   514  var (
   515  	// defaced is NaN(0xdefaced) used as a marker for -Inf weight edges
   516  	// within paths containing negative cycles. Routines marking these
   517  	// edges should use this value.
   518  	defaced = scalar.NaNWith(0xdefaced)
   519  	// defacedBits is the bit pattern we look for in AllShortest to
   520  	// identify the edges.
   521  	defacedBits = math.Float64bits(defaced)
   522  )
   523  
   524  // newAllShortest returns an all-pairs shortest path forest for paths with the
   525  // given nodes. The forward flag indicates whether the path reconstruction is
   526  // performed in the forward (Floyd-Warshall) or reverse (Dijkstra/Johnson's) order.
   527  func newAllShortest(nodes []graph.Node, forward bool) AllShortest {
   528  	if len(nodes) == 0 {
   529  		return AllShortest{}
   530  	}
   531  	indexOf := make(map[int64]int, len(nodes))
   532  	for i, n := range nodes {
   533  		indexOf[n.ID()] = i
   534  	}
   535  	dist := make([]float64, len(nodes)*len(nodes))
   536  	for i := range dist {
   537  		dist[i] = math.Inf(1)
   538  	}
   539  	return AllShortest{
   540  		nodes:   nodes,
   541  		indexOf: indexOf,
   542  
   543  		dist:    mat.NewDense(len(nodes), len(nodes), dist),
   544  		next:    make([][]int, len(nodes)*len(nodes)),
   545  		forward: forward,
   546  	}
   547  }
   548  
   549  // at returns a slice of node indexes into p.nodes for nodes that are mid points
   550  // between nodes indexed by from and to.
   551  func (p AllShortest) at(from, to int) (mid []int) {
   552  	return p.next[from+to*len(p.nodes)]
   553  }
   554  
   555  // set sets the weights of paths between node indexes into p.nodes for from and to
   556  // passing through the nodes indexed by mid.
   557  func (p AllShortest) set(from, to int, weight float64, mid ...int) {
   558  	p.dist.Set(from, to, weight)
   559  	p.next[from+to*len(p.nodes)] = append(p.next[from+to*len(p.nodes)][:0], mid...)
   560  }
   561  
   562  // add adds paths between node indexed in p.nodes by from and to passing through
   563  // the nodes indexed by mid.
   564  func (p AllShortest) add(from, to int, mid ...int) {
   565  loop: // These are likely to be rare, so just loop over collisions.
   566  	for _, k := range mid {
   567  		for _, v := range p.next[from+to*len(p.nodes)] {
   568  			if k == v {
   569  				continue loop
   570  			}
   571  		}
   572  		p.next[from+to*len(p.nodes)] = append(p.next[from+to*len(p.nodes)], k)
   573  	}
   574  }
   575  
   576  // Weight returns the weight of the minimum path between u and v.
   577  func (p AllShortest) Weight(uid, vid int64) float64 {
   578  	from, fromOK := p.indexOf[uid]
   579  	to, toOK := p.indexOf[vid]
   580  	if !fromOK || !toOK {
   581  		return math.Inf(1)
   582  	}
   583  	w := p.dist.At(from, to)
   584  	if math.Float64bits(w) == defacedBits {
   585  		return math.Inf(-1)
   586  	}
   587  	return w
   588  }
   589  
   590  // Between returns a shortest path from u to v and the weight of the path. If more than
   591  // one shortest path exists between u and v, a randomly chosen path will be returned and
   592  // unique is returned false. If a cycle with zero weight exists in the path, it will not
   593  // be included, but unique will be returned false. If a negative cycle exists on the path
   594  // from u to v, path will be returned nil, weight will be -Inf and unique will be false.
   595  func (p AllShortest) Between(uid, vid int64) (path []graph.Node, weight float64, unique bool) {
   596  	from, fromOK := p.indexOf[uid]
   597  	to, toOK := p.indexOf[vid]
   598  	if !fromOK || !toOK || len(p.at(from, to)) == 0 {
   599  		if uid == vid {
   600  			if !fromOK {
   601  				return []graph.Node{node(uid)}, 0, true
   602  			}
   603  			return []graph.Node{p.nodes[from]}, 0, true
   604  		}
   605  		return nil, math.Inf(1), false
   606  	}
   607  
   608  	weight = p.dist.At(from, to)
   609  	if math.Float64bits(weight) == defacedBits {
   610  		return nil, math.Inf(-1), false
   611  	}
   612  
   613  	seen := make([]int, len(p.nodes))
   614  	for i := range seen {
   615  		seen[i] = -1
   616  	}
   617  	var n graph.Node
   618  	if p.forward {
   619  		n = p.nodes[from]
   620  		seen[from] = 0
   621  	} else {
   622  		n = p.nodes[to]
   623  		seen[to] = 0
   624  	}
   625  
   626  	path = []graph.Node{n}
   627  	unique = true
   628  
   629  	var next int
   630  	for from != to {
   631  		c := p.at(from, to)
   632  		if len(c) != 1 {
   633  			unique = false
   634  			next = c[rand.Intn(len(c))]
   635  		} else {
   636  			next = c[0]
   637  		}
   638  		if seen[next] >= 0 {
   639  			path = path[:seen[next]]
   640  		}
   641  		seen[next] = len(path)
   642  		path = append(path, p.nodes[next])
   643  		if p.forward {
   644  			from = next
   645  		} else {
   646  			to = next
   647  		}
   648  	}
   649  	if !p.forward {
   650  		ordered.Reverse(path)
   651  	}
   652  
   653  	return path, weight, unique
   654  }
   655  
   656  // AllBetween returns all shortest paths from u to v and the weight of the paths. Paths
   657  // containing zero-weight cycles are not returned. If a negative cycle exists between
   658  // u and v, paths is returned nil and weight is returned as -Inf.
   659  func (p AllShortest) AllBetween(uid, vid int64) (paths [][]graph.Node, weight float64) {
   660  	from, fromOK := p.indexOf[uid]
   661  	to, toOK := p.indexOf[vid]
   662  	if !fromOK || !toOK || len(p.at(from, to)) == 0 {
   663  		if uid == vid {
   664  			if !fromOK {
   665  				return [][]graph.Node{{node(uid)}}, 0
   666  			}
   667  			return [][]graph.Node{{p.nodes[from]}}, 0
   668  		}
   669  		return nil, math.Inf(1)
   670  	}
   671  
   672  	weight = p.dist.At(from, to)
   673  	if math.Float64bits(weight) == defacedBits {
   674  		return nil, math.Inf(-1)
   675  	}
   676  
   677  	var n graph.Node
   678  	if p.forward {
   679  		n = p.nodes[from]
   680  	} else {
   681  		n = p.nodes[to]
   682  	}
   683  	seen := make([]bool, len(p.nodes))
   684  	paths = p.allBetween(from, to, seen, []graph.Node{n}, nil)
   685  
   686  	return paths, weight
   687  }
   688  
   689  // allBetween recursively constructs a slice of paths extending from the node
   690  // indexed into p.nodes by from to the node indexed by to. len(seen) must match
   691  // the number of nodes held by the receiver. The path parameter is the current
   692  // working path and the results are written into paths.
   693  func (p AllShortest) allBetween(from, to int, seen []bool, path []graph.Node, paths [][]graph.Node) [][]graph.Node {
   694  	if p.forward {
   695  		seen[from] = true
   696  	} else {
   697  		seen[to] = true
   698  	}
   699  	if from == to {
   700  		if path == nil {
   701  			return paths
   702  		}
   703  		if !p.forward {
   704  			ordered.Reverse(path)
   705  		}
   706  		return append(paths, path)
   707  	}
   708  	first := true
   709  	for _, n := range p.at(from, to) {
   710  		if seen[n] {
   711  			continue
   712  		}
   713  		if first {
   714  			path = append([]graph.Node(nil), path...)
   715  			first = false
   716  		}
   717  		if p.forward {
   718  			from = n
   719  		} else {
   720  			to = n
   721  		}
   722  		path = path[:len(path):len(path)]
   723  		paths = p.allBetween(from, to, append([]bool(nil), seen...), append(path, p.nodes[n]), paths)
   724  	}
   725  	return paths
   726  }
   727  
   728  type node int64
   729  
   730  func (n node) ID() int64 { return int64(n) }