1

I'm working with a directed graph in R using igraph and I have a specific issue that I'm unable to resolve. Each vertex carries a weight of 1 and I want to calculate the cumulative sum of the vertices taking into account the following conditions:

  1. "Fiber" routes have priority over 'Micro' routes.
  2. If there are two 'Fiber' or 'Micro' routes, the physical distance in kilometers determines which one is selected.
  3. The solution should not involve removing or adding any edges, i.e., even for calculation purposes, all the existing connections should remain intact.

Here is a simplified example of my graph. For convenience I use R, but it can be in Python:

library(igraph)
library(dplyr)

edges <- tribble(
  ~from,  ~to, ~tipo, ~distance_km, ~color, ~width,
  "A",    "B", "Fiber", 10, "black", 2,
  "B",    "C", "Fiber", 5, "black", 2,
  "B",    "C", "Fiber", 6, "gray", 0.5,
  "A",    "C", "Micro", 5, "gray", 0.5,
  "C",    "D", "Micro", 1, "black", 2,
  "C",    "D", "Micro", 2, "gray", 0.5
)

edges <- edges %>%
  mutate(label = paste0(tipo, " (", distance_km, ")"))

g <- graph_from_data_frame(edges, directed = TRUE)

V(g)$name <- paste0(V(g)$name, " (", 1:4, ")")

plot(g, edge.label = E(g)$label)

How can I calculate the cumulative sum of the vertices following the conditions described above?

In the next image you can see in black the paths that I expect the algorithm must decide to achieve the cumulative sum.

enter image description here

Any guidance or help would be greatly appreciated.

William
  • 164
  • 11

1 Answers1

0

Update

Given a graph with vertex weights wt=1 for all vertices, i.e.,

edges <- edges %>%
    mutate(label = paste0(tipo, " (", distance_km, ")"))

g <- graph_from_data_frame(edges, directed = TRUE) %>%
    set_vertex_attr(name = "wt", value = 1)

the cumulative weights along the desired routing can be obtain like below

v <- names(which(degree(g, mode = "in") == 0))
P <- v
repeat {
    if (degree(g, v, "out") == 0) {
        break
    }
    v <- edges %>%
        filter(from == v) %>%
        arrange(match(tipo, c("Fiber", "Micro")), distance_km) %>%
        slice_head() %>%
        select(to) %>%
        pluck(1)
    P <- append(P, v)
}

gout <- g %>%
    set_vertex_attr(
        name = "cumwt",
        index = match(V(.)$name, P),
        value = cumsum(V(.)$wt[match(V(.)$name, P)])
    )

such that

> gout
IGRAPH 3f25ba4 DN-- 4 6 --
+ attr: name (v/c), wt (v/n), cumwt (v/n), tipo (e/c), distance_km
| (e/n), color (e/c), width (e/n), label (e/c)
+ edges from 3f25ba4 (vertex names):
[1] A->B B->C B->C A->C C->D C->D

> V(gout)
+ 4/4 vertices, named, from 3f25ba4:
[1] A B C D

> V(gout)$wt
[1] 1 1 1 1

> V(gout)$cumwt
[1] 1 2 3 4

Previous: If you want to have a subset of edge dataframe to indicate the routing

Assuming you have one source and one sink only always, then here is my attempt, which works but might be a bit inefficient

route <- c()
v <- names(which(degree(g, mode = "in") == 0))
repeat {
    if (degree(g, v, "out") == 0) {
        break
    }
    p <- edges %>%
        filter(from == v) %>%
        arrange(match(tipo, c("Fiber", "Micro")), distance_km) %>%
        slice_head()
    route <- rbind(route, p)
    v <- p$to
}

and you will obtain the route in a dataframe (from top to bottom)

> route
# A tibble: 3 × 7
  from  to    tipo  distance_km color width label
  <chr> <chr> <chr>       <dbl> <chr> <dbl> <chr>
1 A     B     Fiber          10 black     2 Fiber (10)
2 B     C     Fiber           5 black     2 Fiber (5)
3 C     D     Micro           1 black     2 Micro (1) 
ThomasIsCoding
  • 96,636
  • 9
  • 24
  • 81
  • Thanks a lot @ThomasIsCoding, I'm getting this error when running your code: `Error in if (degree(g, v, "out") == 0) { : argument is of length zero`. Also, from the result you show, I was wondering if I had stated my objective correctly, which is to calculate the cumulative sum given the conditions. Thank you. – William Jun 15 '23 at 21:14
  • @William do you have loops in your graph? I think you'd better provide a more typical example close to your real need. I was just think you want to find the route – ThomasIsCoding Jun 15 '23 at 21:19
  • I'm so sorry for the confusion. My graph is DAG, so it doesn't have loops. The diagram I posted is the simplest and most generalizable example I could think of. What I want is to calculate the cumulative sum. You helped me with that a couple of years ago: https://stackoverflow.com/questions/67528697/finding-the-cumulative-sum-of-the-value-of-nodes-in-a-dag, but now I have to do the same, but given the conditions of cost and type of media (Fiber or Micro). – William Jun 15 '23 at 21:33
  • @William why do you have that error? It works well for me with the example in your question. – ThomasIsCoding Jun 15 '23 at 21:40
  • I already found my mistake. Your code works fine now. – William Jun 15 '23 at 21:53
  • @William See my update – ThomasIsCoding Jun 16 '23 at 07:35
  • I'll check the code and I let you know the results. Thanks in advance – William Jun 20 '23 at 16:20
  • your code works well with the initial "edge" dataframe, but an error arises when I change from "Fiber" to "Micro" (A to B). The error message is: `Error in as.igraph.vs(graph, index) : Invalid vertex name(s)`. I suspect an `NA` value in the `P` route matching might be the issue but I'm unsure how to fix it. – William Jun 20 '23 at 23:00
  • @William You should check the name of graph vertices before using the soluiton. – ThomasIsCoding Jun 21 '23 at 05:54
  • Thanks @ThomasIsCoding, I think I'll see how I figure it out. The important thing is that you've now shown me that my initial example doesn't reflect what I really need. I understand that it works if there is only one source and 'sink', but this is not my situation So I'll open a new question with a more relevant example, thanks for your help. – William Jun 21 '23 at 17:59