Home > Back-end >  How to find a "direct" connected components?
How to find a "direct" connected components?

Time:09-06

I don't know graph theory, so I'm afraid question's title is not property formulated, so I will show a code:

library(magrittr)
library(igraph)

df <- data.frame(from = c(1, 1, 2, 2, 6),
                 to = c(2, 4, 3, 5, 3))

graph_from_data_frame(df) %>% 
  components() %>% 
  membership() %>% 
  stack()
#>   values ind
#> 1      1   1
#> 2      1   2
#> 3      1   6
#> 4      1   4
#> 5      1   3
#> 6      1   5


# find only "direct" paths

data.frame(values = c(1, 1, 2, 1, 1, 1, 2),
           ind = c(1, 2, 6, 4, 3, 5, 3))
#>   values ind
#> 1      1   1
#> 2      1   2
#> 3      2   6
#> 4      1   4
#> 5      1   3
#> 6      1   5
#> 7      2   3

Having a data.frame as above, I know how i can find all connected components, no matter "how" they are connected. But I would like also to be able to find something which is shown at the end of the code block above, i.e. that "6" do not belong to the group "1", but is connected with "3", that's why I have repeated "3" - it belongs to group "1" and "2".

Is there a function for this in igraph or other package in R? But I would prefer igraph. And does this procedure have a name in graph theory? So then I will be able to find some more information about this.

EDIT

Thank you all for help. I have found that for my use case I can use igraph::subcomponent() (I didn't find this function before at the bottom of igraph::component() help page), because at one time I need to find components only for one chosen vertex and I know if I need to find all components connected or just "simple paths" components and, luckily, in this second case it is always vertex "at the end" (beginning?) of path

df <- data.frame(react_id = c("r1", "r1", "r2", "r2", "r6"),
                 depends_on = c("r2", "r4", "r3", "r5", "r3"))

gdf <- igraph::graph_from_data_frame(df)

# get all connected components for specific react_id

igraph::subcomponent(gdf, "r3", "all") |>
  names()
#> [1] "r3" "r2" "r6" "r1" "r5" "r4"

# get "simple paths" components

igraph::subcomponent(gdf, "r1", "out") |>
  names()
#> [1] "r1" "r2" "r4" "r3" "r5"

CodePudding user response:

Something like this?

suppressPackageStartupMessages(
  library(igraph)
)

df <- data.frame(from = c(1, 1, 2, 2, 6),
                 to = c(2, 4, 3, 5, 3))

g <- df |> graph_from_data_frame()
i <- g |> degree(mode = "out") > 0

lapply(V(g)[i], \(x) all_simple_paths(g, from = x, mode = "out"))
#> $`1`
#> $`1`[[1]]
#>   2/6 vertices, named, from c3ceef6:
#> [1] 1 2
#> 
#> $`1`[[2]]
#>   3/6 vertices, named, from c3ceef6:
#> [1] 1 2 3
#> 
#> $`1`[[3]]
#>   3/6 vertices, named, from c3ceef6:
#> [1] 1 2 5
#> 
#> $`1`[[4]]
#>   2/6 vertices, named, from c3ceef6:
#> [1] 1 4
#> 
#> 
#> $`2`
#> $`2`[[1]]
#>   2/6 vertices, named, from c3ceef6:
#> [1] 2 3
#> 
#> $`2`[[2]]
#>   2/6 vertices, named, from c3ceef6:
#> [1] 2 5
#> 
#> 
#> $`6`
#> $`6`[[1]]
#>   2/6 vertices, named, from c3ceef6:
#> [1] 6 3

Created on 2022-09-04 by the reprex package (v2.0.1)

CodePudding user response:

I guess this is thing you are after

lapply(
  V(g)[degree(g, mode = "in") == 0],
  function(x) V(g)[!is.infinite(distances(g, x, mode = "out"))]
)

which gives

$`1`
  5/6 vertices, named, from d7ae5cb:
[1] 1 2 4 3 5

$`6`
  2/6 vertices, named, from d7ae5cb:
[1] 6 3

If you want the result saved in a data.frame, you can try

transform(
  stack(
    lapply(
      V(g)[degree(g, mode = "in") == 0],
      function(x) names(V(g)[!is.infinite(distances(g, x, mode = "out"))])
    )
  ),
  ind = as.integer(factor(ind))
)

which gives

  values ind
1      1   1
2      2   1
3      4   1
4      3   1
5      5   1
6      6   2
7      3   2
  • Related