lnd.xprv/routing/rt/graph/ksp.go

68 lines
1.9 KiB
Go
Raw Normal View History

// Copyright (c) 2016 Bitfury Group Limited
// Distributed under the MIT software license, see the accompanying
// file LICENSE or http://www.opensource.org/licenses/mit-license.php
package graph
import "math"
// KShortestPaths finds k shortest paths
// Note: this implementation finds k path not necessary shortest
// It tries to make that distinct and shortest at the same time
func KShortestPaths(g *Graph, source, target Vertex, k int) ([][]Vertex, error) {
ksp := make([][]Vertex, 0, k)
DRY := make(map[string]bool)
actualNodeWeight := make(map[Vertex]float64, g.GetVertexCount())
for _, id := range g.GetVertexes() {
actualNodeWeight[id] = 1
}
const UselessIterations = 200
for cnt := 0; len(ksp) < k && cnt < UselessIterations; cnt++ {
if err := modifyEdgeWeight(g, actualNodeWeight); err != nil {
return nil, err
}
path, err := DijkstraPath(g, source, target)
if err != nil {
return nil, err
}
for _, v := range path {
actualNodeWeight[v]++
}
key := ""
for _, v := range path {
key += v.String()
}
if !DRY[key] {
DRY[key] = true
ksp = append(ksp, path)
cnt = 0
}
}
return ksp, nil
}
func modifyEdgeWeight(g *Graph, actualNodeWeight map[Vertex]float64) error {
for _, v1 := range g.GetVertexes() {
targets, err := g.GetNeighbors(v1)
if err != nil {
return err
}
for v2, multiedges := range targets {
for ID := range multiedges {
wgt := calcEdgeWeight(actualNodeWeight, v1, v2)
g.ReplaceUndirectedEdge(v1, v2, ID, &ChannelInfo{Wgt: wgt})
}
}
}
return nil
}
// Calculate new edge weight based on vertex weights.
// It uses empirical formulae
// weight(i, j) = (weight(i) + weight(j)) ^ 6
// Number 6 was choosen because it gives best results in several simulations
func calcEdgeWeight(actualNodeWeight map[Vertex]float64, v1, v2 Vertex) float64 {
const ExperiementalNumber = 6.0
wgt := math.Pow(actualNodeWeight[v1]+actualNodeWeight[v2], ExperiementalNumber)
return wgt
}