Skip to content

Commit 72bcb3b

Browse files
dstahlkeaurorarossiKrastanov
authored
Added strong_product, disjunctive_product, lexicographical_product, h… (#154)
Co-authored-by: Aurora Rossi <65721467+aurorarossi@users.noreply.github.com> Co-authored-by: aurorarossi <aurora98rossi@gmail.com> Co-authored-by: Stefan Krastanov <github.acc@krastanov.org>
1 parent 2cfcb1a commit 72bcb3b

File tree

3 files changed

+247
-0
lines changed

3 files changed

+247
-0
lines changed

src/Graphs.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ export
156156
join,
157157
tensor_product,
158158
cartesian_product,
159+
strong_product,
160+
disjunctive_product,
161+
lexicographic_product,
162+
homomorphic_product,
159163
crosspath,
160164
induced_subgraph,
161165
egonet,

src/operators.jl

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,9 @@ end
523523
Return the [cartesian product](https://en.wikipedia.org/wiki/Cartesian_product_of_graphs)
524524
of `g` and `h`.
525525
526+
The cartesian product has edges (g₁, h₁) ∼ (g₂, h₂) when
527+
(g₁ = g₂ ∧ h₁ ∼ h₂) ∨ (g₁ ∼ g₂ ∧ h₁ = h₂).
528+
526529
### Implementation Notes
527530
Preserves the eltype of the input graph. Will error if the number of vertices
528531
in the generated graph exceeds the eltype.
@@ -575,6 +578,8 @@ end
575578
Return the [tensor product](https://en.wikipedia.org/wiki/Tensor_product_of_graphs)
576579
of `g` and `h`.
577580
581+
The tensor product has edges (g₁, h₁) ∼ (g₂, h₂) when g₁ ∼ g₂ ∧ h₁ ∼ h₂.
582+
578583
### Implementation Notes
579584
Preserves the eltype of the input graph. Will error if the number of vertices
580585
in the generated graph exceeds the eltype.
@@ -615,6 +620,227 @@ function tensor_product(g::G, h::G) where {G<:AbstractGraph}
615620
return z
616621
end
617622

623+
"""
624+
strong_product(g, h)
625+
626+
Return the [strong product](https://en.wikipedia.org/wiki/Strong_product_of_graphs)
627+
of `g` and `h`.
628+
629+
The strong product has edges (g₁, h₁) ∼ (g₂, h₂) when
630+
(g₁ = g₂ ∧ h₁ ∼ h₂) ∨ (g₁ ∼ g₂ ∧ h₁ = h₂) ∨ (g₁ ∼ g₂ ∧ h₁ ∼ h₂).
631+
632+
### Implementation Notes
633+
Preserves the eltype of the input graph. Will error if the number of vertices
634+
in the generated graph exceeds the eltype.
635+
636+
# Examples
637+
```jldoctest
638+
julia> using Graphs
639+
640+
julia> a = star_graph(3);
641+
642+
julia> b = path_graph(3);
643+
644+
julia> g = strong_product(a, b)
645+
{9, 20} undirected simple Int64 graph
646+
647+
julia> g == union(cartesian_product(a, b), tensor_product(a, b))
648+
true
649+
```
650+
"""
651+
function strong_product(g::G, h::G) where {G<:AbstractSimpleGraph}
652+
z = G(nv(g) * nv(h))
653+
id(i, j) = (i - 1) * nv(h) + j
654+
undirected = !is_directed(g)
655+
for e1 in edges(g)
656+
i1, i2 = Tuple(e1)
657+
for e2 in edges(h)
658+
j1, j2 = Tuple(e2)
659+
add_edge!(z, id(i1, j1), id(i2, j2))
660+
if undirected
661+
add_edge!(z, id(i1, j2), id(i2, j1))
662+
end
663+
end
664+
end
665+
for e in edges(g)
666+
i1, i2 = Tuple(e)
667+
for j in vertices(h)
668+
add_edge!(z, id(i1, j), id(i2, j))
669+
end
670+
end
671+
for e in edges(h)
672+
j1, j2 = Tuple(e)
673+
for i in vertices(g)
674+
add_edge!(z, id(i, j1), id(i, j2))
675+
end
676+
end
677+
return z
678+
end
679+
680+
"""
681+
disjunctive_product(g, h)
682+
683+
Return the [disjunctive product](https://en.wikipedia.org/wiki/Graph_product)
684+
of `g` and `h`.
685+
686+
The disjunctive product has edges (g₁, h₁) ∼ (g₂, h₂) when g₁ ∼ g₂ ∨ h₁ ∼ h₂.
687+
688+
### Implementation Notes
689+
Preserves the eltype of the input graph. Will error if the number of vertices
690+
in the generated graph exceeds the eltype.
691+
692+
# Examples
693+
```jldoctest
694+
julia> using Graphs
695+
696+
julia> a = star_graph(3);
697+
698+
julia> b = path_graph(3);
699+
700+
julia> g = disjunctive_product(a, b)
701+
{9, 28} undirected simple Int64 graph
702+
703+
julia> complement(g) == strong_product(complement(a), complement(b))
704+
true
705+
```
706+
"""
707+
function disjunctive_product(g::G, h::G) where {G<:AbstractSimpleGraph}
708+
z = G(nv(g) * nv(h))
709+
id(i, j) = (i - 1) * nv(h) + j
710+
for e in edges(g)
711+
i1, i2 = Tuple(e)
712+
for j in vertices(h)
713+
for k in vertices(h)
714+
add_edge!(z, id(i1, j), id(i2, k))
715+
end
716+
end
717+
end
718+
for e in edges(h)
719+
j1, j2 = Tuple(e)
720+
for i in vertices(g)
721+
for k in vertices(g)
722+
add_edge!(z, id(i, j1), id(k, j2))
723+
end
724+
end
725+
end
726+
return z
727+
end
728+
729+
"""
730+
lexicographic_product(g, h)
731+
732+
Return the [lexicographic product](https://en.wikipedia.org/wiki/Lexicographic_product_of_graphs)
733+
of `g` and `h`.
734+
735+
The lexicographic product has edges (g₁, h₁) ∼ (g₂, h₂) when (g₁ ∼ g₂) ∨ (g₁ = g₂ ∧ h₁ ∼ h₂).
736+
737+
### Implementation Notes
738+
Preserves the eltype of the input graph. Will error if the number of vertices
739+
in the generated graph exceeds the eltype.
740+
741+
# Examples
742+
```jldoctest
743+
julia> using Graphs
744+
745+
julia> g = lexicographic_product(star_graph(3), path_graph(3))
746+
{9, 24} undirected simple Int64 graph
747+
748+
julia> adjacency_matrix(g)
749+
9×9 SparseArrays.SparseMatrixCSC{Int64, Int64} with 48 stored entries:
750+
⋅ 1 ⋅ 1 1 1 1 1 1
751+
1 ⋅ 1 1 1 1 1 1 1
752+
⋅ 1 ⋅ 1 1 1 1 1 1
753+
1 1 1 ⋅ 1 ⋅ ⋅ ⋅ ⋅
754+
1 1 1 1 ⋅ 1 ⋅ ⋅ ⋅
755+
1 1 1 ⋅ 1 ⋅ ⋅ ⋅ ⋅
756+
1 1 1 ⋅ ⋅ ⋅ ⋅ 1 ⋅
757+
1 1 1 ⋅ ⋅ ⋅ 1 ⋅ 1
758+
1 1 1 ⋅ ⋅ ⋅ ⋅ 1 ⋅
759+
```
760+
"""
761+
function lexicographic_product(g::G, h::G) where {G<:AbstractSimpleGraph}
762+
z = G(nv(g) * nv(h))
763+
id(i, j) = (i - 1) * nv(h) + j
764+
for e in edges(g)
765+
i1, i2 = Tuple(e)
766+
for j in vertices(h)
767+
for k in vertices(h)
768+
add_edge!(z, id(i1, j), id(i2, k))
769+
end
770+
end
771+
end
772+
for e in edges(h)
773+
j1, j2 = Tuple(e)
774+
for i in vertices(g)
775+
add_edge!(z, id(i, j1), id(i, j2))
776+
end
777+
end
778+
return z
779+
end
780+
781+
"""
782+
homomorphic_product(g, h)
783+
784+
Return the [homomorphic product](https://en.wikipedia.org/wiki/Graph_product)
785+
of `g` and `h`.
786+
787+
The homomorphic product has edges (g₁, h₁) ∼ (g₂, h₂) when
788+
(g₁ = g₂) ∨ (g₁ ∼ g₂ ∧ h₁ ≁ h₂).
789+
790+
### Implementation Notes
791+
Preserves the eltype of the input graph. Will error if the number of vertices
792+
in the generated graph exceeds the eltype.
793+
794+
# Examples
795+
```jldoctest
796+
julia> using Graphs
797+
798+
julia> g = homomorphic_product(star_graph(3), path_graph(3))
799+
{9, 19} undirected simple Int64 graph
800+
801+
julia> adjacency_matrix(g)
802+
9×9 SparseArrays.SparseMatrixCSC{Int64, Int64} with 38 stored entries:
803+
⋅ 1 1 1 ⋅ 1 1 ⋅ 1
804+
1 ⋅ 1 ⋅ 1 ⋅ ⋅ 1 ⋅
805+
1 1 ⋅ 1 ⋅ 1 1 ⋅ 1
806+
1 ⋅ 1 ⋅ 1 1 ⋅ ⋅ ⋅
807+
⋅ 1 ⋅ 1 ⋅ 1 ⋅ ⋅ ⋅
808+
1 ⋅ 1 1 1 ⋅ ⋅ ⋅ ⋅
809+
1 ⋅ 1 ⋅ ⋅ ⋅ ⋅ 1 1
810+
⋅ 1 ⋅ ⋅ ⋅ ⋅ 1 ⋅ 1
811+
1 ⋅ 1 ⋅ ⋅ ⋅ 1 1 ⋅
812+
```
813+
"""
814+
function homomorphic_product(g::G, h::G) where {G<:AbstractSimpleGraph}
815+
z = G(nv(g) * nv(h))
816+
id(i, j) = (i - 1) * nv(h) + j
817+
undirected = !is_directed(g)
818+
for i in vertices(g)
819+
for j in vertices(h)
820+
for k in vertices(h)
821+
if k != j
822+
add_edge!(z, id(i, j), id(i, k))
823+
end
824+
end
825+
end
826+
end
827+
cmpl_h = complement(h)
828+
for e in edges(g)
829+
i1, i2 = Tuple(e)
830+
for f in edges(cmpl_h)
831+
j1, j2 = Tuple(f)
832+
add_edge!(z, id(i1, j1), id(i2, j2))
833+
if undirected
834+
add_edge!(z, id(i1, j2), id(i2, j1))
835+
end
836+
end
837+
for j in vertices(h)
838+
add_edge!(z, id(i1, j), id(i2, j))
839+
end
840+
end
841+
return z
842+
end
843+
618844
## subgraphs ###
619845

620846
"""

test/operators.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,23 @@
271271
end
272272
end
273273

274+
gx = SimpleGraph(10, 20)
275+
gy = SimpleGraph(15, 34)
276+
@testset "Graph product edge counts" for (g1, g2) in zip(testgraphs(gx), testgraphs(gy))
277+
v1 = nv(g1)
278+
v2 = nv(g2)
279+
e1 = ne(g1)
280+
e2 = ne(g2)
281+
# Edge counts from https://en.wikipedia.org/wiki/Graph_product
282+
@test ne(cartesian_product(g1, g2)) == v1 * e2 + v2 * e1
283+
@test ne(tensor_product(g1, g2)) == 2 * e1 * e2
284+
@test ne(lexicographic_product(g1, g2)) == v1 * e2 + e1 * v2^2
285+
@test ne(strong_product(g1, g2)) == v1 * e2 + v2 * e1 + 2 * e1 * e2
286+
@test ne(disjunctive_product(g1, g2)) == v1^2 * e2 + e1 * v2^2 - 2 * e1 * e2
287+
@test ne(homomorphic_product(g1, g2)) ==
288+
v1 * v2 * (v2 - 1) / 2 + e1 * (v2^2 - 2 * e2)
289+
end
290+
274291
## test subgraphs ##
275292

276293
gb = smallgraph(:bull)

0 commit comments

Comments
 (0)