diff --git a/docs/src/api.md b/docs/src/api.md index 8310088..79cf29e 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -52,13 +52,18 @@ Functions that compute properties of the graph: ```@docs nv ne +vertices +has_vertex has_edge edges neighbors all_neighbors +inneighbors +outneighbors degree indegree outdegree density is_bipartite +is_directed ``` \ No newline at end of file diff --git a/src/BipartiteFactorGraphs.jl b/src/BipartiteFactorGraphs.jl index f76d478..f505731 100644 --- a/src/BipartiteFactorGraphs.jl +++ b/src/BipartiteFactorGraphs.jl @@ -2,7 +2,24 @@ module BipartiteFactorGraphs using Graphs import Graphs: - add_edge!, has_edge, edges, neighbors, nv, ne, all_neighbors, degree, indegree, outdegree, density, is_bipartite + AbstractGraph, + vertices, + has_vertex, + add_edge!, + has_edge, + edges, + neighbors, + nv, + ne, + all_neighbors, + inneighbors, + outneighbors, + degree, + indegree, + outdegree, + density, + is_bipartite, + is_directed export BipartiteFactorGraph, add_variable!, @@ -19,6 +36,8 @@ export BipartiteFactorGraph, num_variables, num_factors, # Reexport used Graphs functions + vertices, + has_vertex, add_edge!, has_edge, edges, @@ -26,11 +45,14 @@ export BipartiteFactorGraph, nv, ne, all_neighbors, + inneighbors, + outneighbors, degree, indegree, outdegree, density, - is_bipartite + is_bipartite, + is_directed struct UnorderedPair{T} a::T @@ -97,7 +119,7 @@ struct BipartiteFactorGraph{ DVars <: AbstractDict{Int, TVar}, DFacs <: AbstractDict{Int, TFac}, DE <: AbstractDict{UnorderedPair{Int}, E} -} +} <: AbstractGraph{Int} graph::SimpleGraph{Int} variable_data::DVars factor_data::DFacs @@ -289,6 +311,26 @@ Get the number of factor nodes in the graph. """ num_factors(g::BipartiteFactorGraph) = length(g.factor_data) +""" + vertices(g::BipartiteFactorGraph) + +Get all vertices in the graph. Note, that it returns vertices that represent both variable and factor nodes. +Use [`variables`](@ref) and [`factors`](@ref) to get only variable or factor nodes. +""" +function Graphs.vertices(g::BipartiteFactorGraph) + return Graphs.vertices(g.graph) +end + +""" + has_vertex(g::BipartiteFactorGraph, v::Int) + +Check if vertex `v` is in the graph. Note, that it returns true for both variable and factor nodes. +Use [`is_variable`](@ref) and [`is_factor`](@ref) to check existence of a node with a specific type. +""" +function Graphs.has_vertex(g::BipartiteFactorGraph, v::Int) + return Graphs.has_vertex(g.graph, v) +end + """ has_edge(g::BipartiteFactorGraph, var::Int, fac::Int) @@ -340,6 +382,24 @@ function all_neighbors(g::BipartiteFactorGraph, v::Int) return Graphs.neighbors(g.graph, v) end +""" + inneighbors(g::BipartiteFactorGraph, v::Int) + +Return a list of all in-neighbors of vertex `v` in graph `g`. +""" +function inneighbors(g::BipartiteFactorGraph, v::Int) + return Graphs.inneighbors(g.graph, v) +end + +""" + outneighbors(g::BipartiteFactorGraph, v::Int) + +Return a list of all out-neighbors of vertex `v` in graph `g`. +""" +function outneighbors(g::BipartiteFactorGraph, v::Int) + return Graphs.outneighbors(g.graph, v) +end + """ degree(g::BipartiteFactorGraph[, v]) @@ -405,4 +465,13 @@ function is_bipartite(g::BipartiteFactorGraph) return Graphs.is_bipartite(g.graph) end +""" + is_directed(g::BipartiteFactorGraph) + +Check if the graph is directed. For BipartiteFactorGraph this is always false since the graph is undirected. +""" +function is_directed(g::BipartiteFactorGraph) + return false +end + end # module diff --git a/test/graph_api_tests.jl b/test/graph_api_tests.jl index 24cf1ae..e9d70c2 100644 --- a/test/graph_api_tests.jl +++ b/test/graph_api_tests.jl @@ -4,10 +4,15 @@ g = BipartiteFactorGraph(Float64, String, Bool) + @test !is_directed(g) + # Test empty graph properties @test Graphs.nv(g) == 0 @test Graphs.ne(g) == 0 @test Graphs.density(g) == 0.0 + @test Graphs.eltype(g) == Int + + @test isempty(vertices(g)) # Add some nodes and edges v1 = add_variable!(g, 1.0) @@ -17,8 +22,43 @@ f1 = add_factor!(g, "factor1") f2 = add_factor!(g, "factor2") + @test !isempty(vertices(g)) + @test length(vertices(g)) == 5 @test length(edges(g)) == 0 + @test v1 in vertices(g) + @test f1 in vertices(g) + @test v2 in vertices(g) + @test f2 in vertices(g) + @test v3 in vertices(g) + + @test v1 in variables(g) + @test v2 in variables(g) + @test v3 in variables(g) + + @test f1 in factors(g) + @test f2 in factors(g) + + @test !(v1 in factors(g)) + @test !(v2 in factors(g)) + @test !(v3 in factors(g)) + + @test !(f1 in variables(g)) + @test !(f2 in variables(g)) + + @test has_vertex(g, v1) + @test has_vertex(g, v2) + @test has_vertex(g, v3) + @test has_vertex(g, f1) + @test has_vertex(g, f2) + @test !has_vertex(g, -1) + + @test !has_edge(g, v1, f1) + @test !has_edge(g, v2, f1) + @test !has_edge(g, v2, f2) + @test !has_edge(g, v3, f2) + @test !has_edge(g, v1, f2) + add_edge!(g, v1, f1, true) add_edge!(g, v2, f1, true) add_edge!(g, v2, f2, false) @@ -26,6 +66,24 @@ @test length(edges(g)) == 4 + @test has_edge(g, v1, f1) + @test has_edge(g, v2, f1) + @test has_edge(g, v2, f2) + @test has_edge(g, v3, f2) + @test !has_edge(g, v1, f2) + + @test inneighbors(g, v1) == [f1] + @test inneighbors(g, v2) == [f1, f2] + @test inneighbors(g, v3) == [f2] + @test inneighbors(g, f1) == [v1, v2] + @test inneighbors(g, f2) == [v2, v3] + + @test outneighbors(g, v1) == [f1] + @test outneighbors(g, v2) == [f1, f2] + @test outneighbors(g, v3) == [f2] + @test outneighbors(g, f1) == [v1, v2] + @test outneighbors(g, f2) == [v2, v3] + # Test graph properties @test Graphs.nv(g) == 5 # 3 variables + 2 factors @test Graphs.ne(g) == 4 # 4 edges