327768f4ad
Use [33]byte for graph vertex representation. Delete unneeded stuff: 1. DeepEqual for graph comparison 2. EdgePath 3. 2-thread BFS 4. Table transfer messages and neighborhood radius 5. Beacons Refactor: 1. Change ID to Vertex 2. Test use table driven approach 3. Add comments 4. Make graph internal representation private 5. Use wire.OutPoint as EdgeId 6. Decouple routing messages from routing implementation 7. Delete Async methods 8. Delete unneeded channels and priority buffer from manager 9. Delete unneeded interfaces in internal graph realisation 10. Renamed ID to Vertex
68 lines
1.9 KiB
Go
68 lines
1.9 KiB
Go
// 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
|
|
} |