For a node \(v\) that has children, the B-sets are the intersections of the parents sets of the children of \(v\) with \(v\)’s own parents sets.
They can be obtained using the function
DAG = create_empty_DAG(6)
DAG = bnlearn::set.arc(DAG, 'U1', 'U5')
DAG = bnlearn::set.arc(DAG, 'U2', 'U5')
DAG = bnlearn::set.arc(DAG, 'U3', 'U5')
DAG = bnlearn::set.arc(DAG, 'U4', 'U5')
DAG = bnlearn::set.arc(DAG, 'U1', 'U6')
DAG = bnlearn::set.arc(DAG, 'U2', 'U6')
DAG = bnlearn::set.arc(DAG, 'U5', 'U6')DAG |> bnlearn::as.igraph() |>
igraph::plot.igraph(size = 10, label.cex = 1, layout = igraph::layout_as_tree
)find_B_sets_v(DAG, v = 'U5')
#> U1 U2 U3 U4
#> Empty B-set FALSE FALSE FALSE FALSE
#> U6 TRUE TRUE FALSE FALSE
#> Full B-set TRUE TRUE TRUE TRUEThis means that for v = U5, the B-sets corresponding to
U6 is made up of U1 and U2. By
convention, the empty set and the full set of parents of v
are always added. To obtain all the B-sets of the nodes of the graph,
the following code can be used:
B_sets = find_B_sets(DAG)
B_sets$B_sets
#> $U1
#>
#> [1,]
#> [2,]
#> [3,]
#> [4,]
#>
#> $U2
#>
#> [1,]
#> [2,]
#> [3,]
#> [4,]
#>
#> $U3
#>
#> [1,]
#> [2,]
#> [3,]
#>
#> $U4
#>
#> [1,]
#> [2,]
#> [3,]
#>
#> $U5
#> U1 U2 U3 U4
#> Empty B-set FALSE FALSE FALSE FALSE
#> U6 TRUE TRUE FALSE FALSE
#> Full B-set TRUE TRUE TRUE TRUE
#>
#> $U6
#> U1 U2 U5
#> Empty B-set FALSE FALSE FALSE
#> Full B-set TRUE TRUE TRUEAn interfering v-structure is by definition a case when two B-sets of the same node are not comparable (for the inclusion order, i.e. neither of them is included in the other one).
Here is an example of a graph with interfering v-structures.
DAG = create_empty_DAG(5)
DAG = bnlearn::set.arc(DAG, 'U1', 'U3')
DAG = bnlearn::set.arc(DAG, 'U2', 'U3')
DAG = bnlearn::set.arc(DAG, 'U1', 'U4')
DAG = bnlearn::set.arc(DAG, 'U3', 'U4')
DAG = bnlearn::set.arc(DAG, 'U2', 'U5')
DAG = bnlearn::set.arc(DAG, 'U3', 'U5')find_B_sets_v(DAG, v = 'U3')
#> U1 U2
#> Empty B-set FALSE FALSE
#> U4 TRUE FALSE
#> U5 FALSE TRUE
#> Full B-set TRUE TRUETo check automatically that the B-sets are not comparable (i.e. the existence of a v-structure), we can do:
More generally, the presence of v-structures can be automatically checked using the following function:
To find the interfering v-structures at a given node, we can use:
find_B_sets_v(DAG, v = 'U3') |>
find_interfering_v_from_B_sets() |>
print()
#> A B parents.A.but.not.parents.B parents.B.but.not.parents.A
#> 1 U4 U5 U1 U2To fix this, we can add one of the missing arcs. This makes the interfering v-structure disappear.
In this case, the B-sets are:
If there are no interfering v-structures, the B-sets are sorted. We can then get their increments as follows:
find_B_sets_v(DAG, v = 'U3') |>
B_sets_cut_increments()
#> [[1]]
#> [1] "U1"
#>
#> [[2]]
#> [1] "U2"
#>
#> [[3]]
#> character(0)In this case, the B-sets of U5 and the full B-set are
identical. Therefore, the last increment is the empty character vector.
It can be nice sometimes to make the B-sets unique so as to avoid
this.