Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added strong_product, disjunctive_product, lexicographical_product, h… #154

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
7 changes: 4 additions & 3 deletions src/Graphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ MinkowskiCost, BoundedMinkowskiCost,

# operators
complement, reverse, reverse!, blockdiag, union, intersect,
difference, symmetric_difference,
join, tensor_product, cartesian_product, crosspath,
induced_subgraph, egonet, merge_vertices!, merge_vertices,
difference, symmetric_difference, join,
tensor_product, cartesian_product, strong_product, disjunctive_product,
lexicographic_product, homomorphic_product,
crosspath, induced_subgraph, egonet, merge_vertices!, merge_vertices,

# bfs
gdistances, gdistances!, bfs_tree, bfs_parents, has_path,
Expand Down
211 changes: 211 additions & 0 deletions src/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,217 @@ function tensor_product(g::G, h::G) where G <: AbstractGraph
return z
end

"""
strong_product(g, h)

Return the [strong product](https://en.wikipedia.org/wiki/Strong_product_of_graphs)
of `g` and `h`.
dstahlke marked this conversation as resolved.
Show resolved Hide resolved

### Implementation Notes
Preserves the eltype of the input graph. Will error if the number of vertices
in the generated graph exceeds the eltype.

# Examples
```jldoctest
julia> using Graphs

julia> a = star_graph(3)

julia> b = path_graph(3)

julia> g = strong_product(a, b)
{9, 8} undirected simple Int64 graph

julia> g == union(cartesian_product(a, b), tensor_product(a, b))
true
```
"""
function strong_product(g::G, h::G) where G <: AbstractGraph
z = G(nv(g) * nv(h))
id(i, j) = (i - 1) * nv(h) + j
undirected = !is_directed(g)
for e1 in edges(g)
i1, i2 = Tuple(e1)
for e2 in edges(h)
j1, j2 = Tuple(e2)
add_edge!(z, id(i1, j1), id(i2, j2))
if undirected
add_edge!(z, id(i1, j2), id(i2, j1))
end
end
end
for e in edges(g)
i1, i2 = Tuple(e)
for j = vertices(h)
add_edge!(z, id(i1, j), id(i2, j))
end
end
for e in edges(h)
j1, j2 = Tuple(e)
for i in vertices(g)
add_edge!(z, id(i, j1), id(i, j2))
end
end
return z
end

"""
disjunctive_product(g, h)

Return the [disjunctive product](https://en.wikipedia.org/wiki/Graph_product)
of `g` and `h`.

### Implementation Notes
Preserves the eltype of the input graph. Will error if the number of vertices
in the generated graph exceeds the eltype.

# Examples
```jldoctest
julia> using Graphs

julia> a = star_graph(3)

julia> b = path_graph(3)

julia> g = disjunctive_product(a, b)
{9, 8} undirected simple Int64 graph

julia> complement(g) == strong_product(complement(a), complement(b))
true
```
"""
function disjunctive_product(g::G, h::G) where G <: AbstractGraph
z = G(nv(g) * nv(h))
id(i, j) = (i - 1) * nv(h) + j
for e in edges(g)
i1, i2 = Tuple(e)
for j = vertices(h)
for k = vertices(h)
add_edge!(z, id(i1, j), id(i2, k))
end
end
end
for e in edges(h)
j1, j2 = Tuple(e)
for i in vertices(g)
for k in vertices(g)
add_edge!(z, id(i, j1), id(k, j2))
end
end
end
return z
end

"""
lexicographic_product(g, h)

Return the [lexicographic product](https://en.wikipedia.org/wiki/Lexicographic_product_of_graphs)
of `g` and `h`.

### Implementation Notes
Preserves the eltype of the input graph. Will error if the number of vertices
in the generated graph exceeds the eltype.

# Examples
```jldoctest
julia> using Graphs

julia> g = lexicographic_product(star_graph(3), path_graph(3))
{9, 8} undirected simple Int64 graph

julia> adjacency_matrix(g)
9×9 SparseArrays.SparseMatrixCSC{Int64, Int64} with 48 stored entries:
⋅ 1 ⋅ 1 1 1 1 1 1
1 ⋅ 1 1 1 1 1 1 1
⋅ 1 ⋅ 1 1 1 1 1 1
1 1 1 ⋅ 1 ⋅ ⋅ ⋅ ⋅
1 1 1 1 ⋅ 1 ⋅ ⋅ ⋅
1 1 1 ⋅ 1 ⋅ ⋅ ⋅ ⋅
1 1 1 ⋅ ⋅ ⋅ ⋅ 1 ⋅
1 1 1 ⋅ ⋅ ⋅ 1 ⋅ 1
1 1 1 ⋅ ⋅ ⋅ ⋅ 1 ⋅
```
"""
function lexicographic_product(g::G, h::G) where G <: AbstractGraph
z = G(nv(g) * nv(h))
id(i, j) = (i - 1) * nv(h) + j
for e in edges(g)
i1, i2 = Tuple(e)
for j = vertices(h)
for k = vertices(h)
add_edge!(z, id(i1, j), id(i2, k))
end
end
end
for e in edges(h)
j1, j2 = Tuple(e)
for i in vertices(g)
add_edge!(z, id(i, j1), id(i, j2))
end
end
return z
end

"""
homomorphic_product(g, h)

Return the [homomorphic product](https://en.wikipedia.org/wiki/Graph_product)
of `g` and `h`.

### Implementation Notes
Preserves the eltype of the input graph. Will error if the number of vertices
in the generated graph exceeds the eltype.

# Examples
```jldoctest
julia> using Graphs

julia> g = homomorphic_product(star_graph(3), path_graph(3))
{9, 8} undirected simple Int64 graph

julia> adjacency_matrix(g)
9×9 SparseArrays.SparseMatrixCSC{Int64, Int64} with 38 stored entries:
⋅ 1 1 1 ⋅ 1 1 ⋅ 1
1 ⋅ 1 ⋅ 1 ⋅ ⋅ 1 ⋅
1 1 ⋅ 1 ⋅ 1 1 ⋅ 1
1 ⋅ 1 ⋅ 1 1 ⋅ ⋅ ⋅
⋅ 1 ⋅ 1 ⋅ 1 ⋅ ⋅ ⋅
1 ⋅ 1 1 1 ⋅ ⋅ ⋅ ⋅
1 ⋅ 1 ⋅ ⋅ ⋅ ⋅ 1 1
⋅ 1 ⋅ ⋅ ⋅ ⋅ 1 ⋅ 1
1 ⋅ 1 ⋅ ⋅ ⋅ 1 1 ⋅
```
"""
function homomorphic_product(g::G, h::G) where G <: AbstractGraph
z = G(nv(g) * nv(h))
id(i, j) = (i - 1) * nv(h) + j
undirected = !is_directed(g)
for i in vertices(g)
for j in vertices(h)
for k in vertices(h)
if k != j
add_edge!(z, id(i, j), id(i, k))
end
end
end
end
cmpl_h = complement(h)
for e in edges(g)
i1, i2 = Tuple(e)
for f in edges(cmpl_h)
j1, j2 = Tuple(f)
add_edge!(z, id(i1, j1), id(i2, j2))
if undirected
add_edge!(z, id(i1, j2), id(i2, j1))
end
end
for j in vertices(h)
add_edge!(z, id(i1, j), id(i2, j))
end
end
return z
end


## subgraphs ###

Expand Down
15 changes: 15 additions & 0 deletions test/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,21 @@
end
end

gx = SimpleGraph(100, 200)
@testset "Graph product edge counts: $g" for g in testgraphs(gx)
gy = SimpleGraph(123, 234)
v1 = nv(gx)
v2 = nv(gy)
e1 = ne(gx)
e2 = ne(gy)
# Edge counts from https://en.wikipedia.org/wiki/Graph_product
@test ne(cartesian_product(gx, gy)) == v1*e2 + v2*e1
@test ne(tensor_product(gx, gy)) == 2*e1*e2
@test ne(lexicographic_product(gx, gy)) == v1*e2 + e1*v2^2
@test ne(strong_product(gx, gy)) == v1*e2 + v2*e1 + 2*e1*e2
@test ne(disjunctive_product(gx, gy)) == v1^2*e2 + e1*v2^2 - 2*e1*e2
end
dstahlke marked this conversation as resolved.
Show resolved Hide resolved

## test subgraphs ##

gb = smallgraph(:bull)
Expand Down