13

I am trying to implement the Kou's algorithm to identify Steiner Tree(s) in R using igraph.

The Kou's algorithm can be described like this:

  1. Find the complete distance graph G' (G' has V' = S (steiner nodes) , and for each pair of nodes (u,v) in VxV there is an edge with weight equal to the weight of the min-cost path between these nodes p_(u,v) in G)
  2. Find a minimum spanning tree T' in G'
  3. Construct the subgraph Gs, of G by substituting every edge of T', which is an edge of G' with the corresponding shortest path of G (it there are several shortest paths, pick an arbitrary one).
  4. Find the minimal spanning tree, Ts, of Gs (If there are several minimal spanning trees, pick an arbitrary one)
  5. Construct a Steiner tree, Th, from Ts by deleting edges in Ts, if necessary, to that all the leaves in Th are Steiner nodes.

The first 2 steps are easy:

g <- erdos.renyi.game(100, 1/10) # graph
V(g)$name <- 1:100

# Some steiner nodes
steiner.points <- sample(1:100, 5)

# Complete distance graph G'
Gi <- graph.full(5)
V(Gi)$name <- steiner.points

# Find a minimum spanning tree T' in G'
mst <- minimum.spanning.tree(Gi)

However, I don't know how to replace the edges in T' for the shortest path in G. I know that with get.shortest.paths I can get the vpath from a pair of nodes, but how I replace and edge in T' with the shortest.path in G?

Many thanks in advance

Martin Thorsen Ranang
  • 2,394
  • 1
  • 28
  • 43
user2380782
  • 1,542
  • 4
  • 22
  • 60

1 Answers1

7

If I'm understanding the algorithm as you've written it, I think this gets you through step 3, but please clarify if that's not the case:

library(igraph)

set.seed(2002)

g <- erdos.renyi.game(100, 1/10) # graph
V(g)$name <- as.character(1:100)

## Some steiner nodes:
steiner.points <- sample(1:100, 5)

## Complete distance graph G'
Gi <- graph.full(5)
V(Gi)$name <- steiner.points

## Find a minimum spanning tree T' in G'
mst <- minimum.spanning.tree(Gi)

##  For each edge in mst, replace with shortest path:
edge_list <- get.edgelist(mst)

Gs <- mst
for (n in 1:nrow(edge_list)) {
    i <- edge_list[n,2]
    j <- edge_list[n,1]
    ##  If the edge of T' mst is shared by Gi, then remove the edge from T'
    ##    and replace with the shortest path between the nodes of g: 
    if (length(E(Gi)[which(V(mst)$name==i) %--% which(V(mst)$name==j)]) == 1) {
        ##  If edge is present then remove existing edge from the 
        ##    minimum spanning tree:
        Gs <- Gs - E(Gs)[which(V(mst)$name==i) %--% which(V(mst)$name==j)]

        ##  Next extract the sub-graph from g corresponding to the 
        ##    shortest path and union it with the mst graph:
        g_sub <- induced.subgraph(g, (get.shortest.paths(g, from=V(g)[i], to=V(g)[j])$vpath[[1]]))
        Gs <- graph.union(Gs, g_sub, byname=T)
  }
}

par(mfrow=c(1,2))
plot(mst)
plot(Gs)

Plot of minimum spanning tree on the left, replaced with shortest paths on right:

network plots

Forrest R. Stevens
  • 3,435
  • 13
  • 21
  • Thanks @Forrest, however all the edges in the `mst` should be replaced for shorthest paths (in case of multiple shortest path, then randomly pick one). I attach a link with the method where you can see a graphical example http://www.cs.umaine.edu/~markov/SteinerTrees.pdf – user2380782 May 12 '15 at 20:12
  • I'm unsure which edges you're referring to I guess. The figure on the left is the minimum spanning tree that you calculated. The figure on the right has every edge replaced by the shortest path from the original graph `g` except for edge `1 %--% 100` which in the simulated data is a direct connection (nodes 1 and 100 are neighbors). Please help me if I'm missing something? – Forrest R. Stevens May 12 '15 at 20:38