routing: replace linear vertex scan with distanceHeap usage
In this commit we now utilize the node distance heap that was added in a prior commit into our core path finding logic. With this new data structure, we no longer linearly scan the distance of all vertexes from the source node when deciding which one to greedily explore. Instead, we now start with the source added to our distance heap, then new vertexes are progressively added to our heap as their edges are explored. With this change, we move the computational complexity of our path finding algorithm closer to the theoretical limit.
This commit is contained in:
parent
20aba8060f
commit
b6199f27da
@ -3,6 +3,8 @@ package routing
|
|||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"container/heap"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/roasbeef/btcd/btcec"
|
"github.com/roasbeef/btcd/btcec"
|
||||||
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
||||||
@ -239,11 +241,11 @@ func edgeWeight(e *channeldb.ChannelEdgePolicy) float64 {
|
|||||||
func findRoute(graph *channeldb.ChannelGraph, target *btcec.PublicKey,
|
func findRoute(graph *channeldb.ChannelGraph, target *btcec.PublicKey,
|
||||||
amt btcutil.Amount) (*Route, error) {
|
amt btcutil.Amount) (*Route, error) {
|
||||||
|
|
||||||
// First initialize empty list of all the node that we've yet to
|
|
||||||
// visited.
|
// First we'll initilaze an empty heap which'll help us to quickly
|
||||||
// TODO(roasbeef): make into incremental fibonacci heap rather than
|
// locate the next edge we should visit next during our graph
|
||||||
// loading all into memory.
|
// traversal.
|
||||||
var unvisited []*channeldb.LightningNode
|
var nodeHeap distanceHeap
|
||||||
|
|
||||||
// For each node/vertex the graph we create an entry in the distance
|
// For each node/vertex the graph we create an entry in the distance
|
||||||
// map for the node set with a distance of "infinity". We also mark
|
// map for the node set with a distance of "infinity". We also mark
|
||||||
@ -256,8 +258,6 @@ func findRoute(graph *channeldb.ChannelGraph, target *btcec.PublicKey,
|
|||||||
dist: infinity,
|
dist: infinity,
|
||||||
node: node,
|
node: node,
|
||||||
}
|
}
|
||||||
|
|
||||||
unvisited = append(unvisited, node)
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -276,39 +276,23 @@ func findRoute(graph *channeldb.ChannelGraph, target *btcec.PublicKey,
|
|||||||
node: sourceNode,
|
node: sourceNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To start, our source node will hte the sole item within our distance
|
||||||
|
// heap.
|
||||||
|
heap.Push(&nodeHeap, distance[sourceVertex])
|
||||||
|
|
||||||
// We'll use this map as a series of "previous" hop pointers. So to get
|
// We'll use this map as a series of "previous" hop pointers. So to get
|
||||||
// to `vertex` we'll take the edge that it's mapped to within `prev`.
|
// to `vertex` we'll take the edge that it's mapped to within `prev`.
|
||||||
prev := make(map[vertex]edgeWithPrev)
|
prev := make(map[vertex]edgeWithPrev)
|
||||||
|
|
||||||
for len(unvisited) != 0 {
|
for nodeHeap.Len() != 0 {
|
||||||
var bestNode *channeldb.LightningNode
|
// Fetch the node within the smallest distance from our source
|
||||||
smallestDist := infinity
|
// from the heap.
|
||||||
|
bestNode := heap.Pop(&nodeHeap).(nodeWithDist).node
|
||||||
// First we examine our list of unvisited nodes, for the most
|
|
||||||
// optimal vertex to examine next.
|
|
||||||
for i, node := range unvisited {
|
|
||||||
// The "best" node to visit next is node with the
|
|
||||||
// smallest distance from the source of all the
|
|
||||||
// unvisited nodes.
|
|
||||||
v := newVertex(node.PubKey)
|
|
||||||
if nodeInfo := distance[v]; nodeInfo.dist < smallestDist {
|
|
||||||
smallestDist = nodeInfo.dist
|
|
||||||
bestNode = nodeInfo.node
|
|
||||||
|
|
||||||
// Since we're going to visit this node, we can
|
|
||||||
// remove it from the set of unvisited nodes.
|
|
||||||
copy(unvisited[i:], unvisited[i+1:])
|
|
||||||
unvisited[len(unvisited)-1] = nil // Avoid GC leak.
|
|
||||||
unvisited = unvisited[:len(unvisited)-1]
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we've reached our target (or we don't have any outgoing
|
// If we've reached our target (or we don't have any outgoing
|
||||||
// edges), then we're done here and can exit the graph
|
// edges), then we're done here and can exit the graph
|
||||||
// traversal early.
|
// traversal early.
|
||||||
if bestNode == nil || bestNode.PubKey.IsEqual(target) {
|
if bestNode.PubKey.IsEqual(target) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,9 +311,9 @@ func findRoute(graph *channeldb.ChannelGraph, target *btcec.PublicKey,
|
|||||||
// If this new tentative distance is better than the
|
// If this new tentative distance is better than the
|
||||||
// current best known distance to this node, then we
|
// current best known distance to this node, then we
|
||||||
// record the new better distance, and also populate
|
// record the new better distance, and also populate
|
||||||
// our "next hop" map with this edge.
|
// our "next hop" map with this edge. We'll also shave
|
||||||
// TODO(roasbeef): add capacity to relaxation criteria?
|
// off irrelevant edges by adding the sufficient
|
||||||
// * also add min payment?
|
// capacity of an edge to our relaxation condition.
|
||||||
v := newVertex(edge.Node.PubKey)
|
v := newVertex(edge.Node.PubKey)
|
||||||
if tempDist < distance[v].dist &&
|
if tempDist < distance[v].dist &&
|
||||||
edgeInfo.Capacity >= amt {
|
edgeInfo.Capacity >= amt {
|
||||||
@ -345,6 +329,10 @@ func findRoute(graph *channeldb.ChannelGraph, target *btcec.PublicKey,
|
|||||||
},
|
},
|
||||||
prevNode: bestNode.PubKey,
|
prevNode: bestNode.PubKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add this new node to our heap as we'd like
|
||||||
|
// to further explore down this edge.
|
||||||
|
heap.Push(&nodeHeap, distance[v])
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user