autopilot/interface+prefattach: scale node scores to range [0.0, 1.0]

To prepare for combinning scores from multiple heuristics, we require the
scores returned from the NodeSores API to be in the range [0.0, 1.0].

The prefAttach heuristic is altered to scale the returned scores such
that the most connected node in the grpah is given a score of 1.0.
This commit is contained in:
Johan T. Halseth 2019-01-09 09:14:45 +01:00
parent 4537c63dbd
commit 592ce92c72
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26
3 changed files with 24 additions and 17 deletions

@ -125,11 +125,12 @@ type AttachmentHeuristic interface {
// returned channel candidates maps the NodeID to a NodeScore for the
// node.
//
// The scores will be in the range [0, M], where 0 indicates no
// improvement in connectivity if a channel is opened to this node,
// while M is the maximum possible improvement in connectivity. The
// size of M is up to the implementation of this interface, so scores
// must be normalized if compared against other implementations.
// The returned scores will be in the range [0, 1.0], where 0 indicates
// no improvement in connectivity if a channel is opened to this node,
// while 1.0 is the maximum possible improvement in connectivity. The
// implementation of this interface must return scores in this range to
// properly allow the autopilot agent to make a reasonable choice based
// on the score from multiple heuristics.
//
// NOTE: A NodeID not found in the returned map is implicitly given a
// score of 0.

@ -43,9 +43,10 @@ func NewNodeID(pub *btcec.PublicKey) NodeID {
return n
}
// NodeScores is a method that given the current channel graph and
// current set of local channels, scores the given nodes according to
// the preference of opening a channel of the given size with them.
// NodeScores is a method that given the current channel graph and current set
// of local channels, scores the given nodes according to the preference of
// opening a channel of the given size with them. The returned channel
// candidates maps the NodeID to a NodeScore for the node.
//
// The heuristic employed by this method is one that attempts to promote a
// scale-free network globally, via local attachment preferences for new nodes
@ -64,21 +65,25 @@ func (p *PrefAttachment) NodeScores(g ChannelGraph, chans []Channel,
chanSize btcutil.Amount, nodes map[NodeID]struct{}) (
map[NodeID]*NodeScore, error) {
// Count the number of channels in the graph. We'll also count the
// number of channels as we go for the nodes we are interested in.
var graphChans int
// Count the number of channels for each particular node in the graph.
var maxChans int
nodeChanNum := make(map[NodeID]int)
if err := g.ForEachNode(func(n Node) error {
var nodeChans int
err := n.ForEachChannel(func(_ ChannelEdge) error {
nodeChans++
graphChans++
return nil
})
if err != nil {
return err
}
// We keep track of the highest-degree node we've seen, as this
// will be given the max score.
if nodeChans > maxChans {
maxChans = nodeChans
}
// If this node is not among our nodes to score, we can return
// early.
nID := NodeID(n.PubKey())
@ -97,7 +102,7 @@ func (p *PrefAttachment) NodeScores(g ChannelGraph, chans []Channel,
// If there are no channels in the graph we cannot determine any
// preferences, so we return, indicating all candidates get a score of
// zero.
if graphChans == 0 {
if maxChans == 0 {
return nil, nil
}
@ -127,8 +132,9 @@ func (p *PrefAttachment) NodeScores(g ChannelGraph, chans []Channel,
}
// Otherwise we score the node according to its fraction of
// channels in the graph.
score := float64(nodeChans) / float64(graphChans)
// channels in the graph, scaled such that the highest-degree
// node will be given a score of 1.0.
score := float64(nodeChans) / float64(maxChans)
candidates[nID] = &NodeScore{
NodeID: nID,
Score: score,

@ -249,8 +249,8 @@ func TestPrefAttachmentSelectTwoVertexes(t *testing.T) {
// Since each of the nodes has 1 channel, out
// of only one channel in the graph, we expect
// their score to be 0.5.
expScore := float64(0.5)
// their score to be 1.0.
expScore := float64(1.0)
if candidate.Score != expScore {
t1.Fatalf("expected candidate score "+
"to be %v, instead was %v",