Skip to content

Commit 6f98da9

Browse files
committed
initial nautygraphext implementation
1 parent 12ac6ba commit 6f98da9

File tree

11 files changed

+327
-36
lines changed

11 files changed

+327
-36
lines changed

Project.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ SimpleTraits = "699a6c99-e7fa-54fc-8d76-47d257e15c1d"
1515
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
1616
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
1717

18+
[weakdeps]
19+
NautyGraphs = "7509a0a4-015a-4167-b44b-0799a1a2605e"
20+
21+
[extensions]
22+
NautyGraphsExt = "NautyGraphs"
23+
1824
[compat]
1925
Aqua = "0.6"
2026
ArnoldiMethod = "0.4"
@@ -23,6 +29,7 @@ DataStructures = "0.17, 0.18"
2329
Documenter = "0.27"
2430
Inflate = "0.1.3"
2531
JuliaFormatter = "1"
32+
NautyGraphs = "0.5.0"
2633
SimpleTraits = "0.9"
2734
StableRNGs = "1"
2835
Statistics = "1"
@@ -36,6 +43,7 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
3643
JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"
3744
JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899"
3845
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
46+
NautyGraphs = "7509a0a4-015a-4167-b44b-0799a1a2605e"
3947
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
4048
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
4149
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
@@ -45,4 +53,4 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
4553
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
4654

4755
[targets]
48-
test = ["Aqua", "Base64", "DelimitedFiles", "Documenter", "JET", "JuliaFormatter", "LinearAlgebra", "Pkg", "Random", "SparseArrays", "StableRNGs", "Statistics", "Test", "Unitful"]
56+
test = ["Aqua", "Base64", "DelimitedFiles", "Documenter", "JET", "JuliaFormatter", "LinearAlgebra", "NautyGraphs", "Pkg", "Random", "SparseArrays", "StableRNGs", "Statistics", "Test", "Unitful"]

ext/NautyGraphsExt.jl

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
module NautyGraphsExt
2+
3+
using Graphs, NautyGraphs
4+
using Graphs.Experimental: AlgNautyGraphs
5+
6+
function Graphs.Experimental.has_induced_subgraphisomorph(
7+
g1::AbstractGraph,
8+
g2::AbstractGraph,
9+
::AlgNautyGraphs;
10+
vertex_relation::Union{Nothing,Function}=nothing,
11+
edge_relation::Union{Nothing,Function}=nothing,
12+
)::Bool
13+
error(
14+
"Induced subgraph isomorphims are currently not supported by `NautyGraphs`. Please use a different isomorphism algorithm.",
15+
)
16+
return nothing
17+
end
18+
19+
function Graphs.Experimental.has_subgraphisomorph(
20+
g1::AbstractGraph,
21+
g2::AbstractGraph,
22+
::AlgNautyGraphs;
23+
vertex_relation::Union{Nothing,Function}=nothing,
24+
edge_relation::Union{Nothing,Function}=nothing,
25+
)::Bool
26+
error(
27+
"Subgraph isomorphims are currently not supported by `NautyGraphs`. Please use a different isomorphism algorithm.",
28+
)
29+
return nothing
30+
end
31+
32+
function Graphs.Experimental.has_isomorph(
33+
g1::AbstractGraph,
34+
g2::AbstractGraph,
35+
::AlgNautyGraphs;
36+
vertex_relation::Union{Nothing,Function}=nothing,
37+
edge_relation::Union{Nothing,Function}=nothing,
38+
)::Bool
39+
if !isnothing(edge_relation)
40+
error(
41+
"Edge relations are currently not supported by `NautyGraphs`. Please use a different isomorphism algorithm.",
42+
)
43+
end
44+
if !isnothing(vertex_relation)
45+
error(
46+
"Vertex relations are currently not supported by `NautyGraphs`. Please use a different isomorphism algorithm.",
47+
)
48+
end
49+
return NautyGraph(g1) NautyGraph(g2)
50+
end
51+
52+
function Graphs.Experimental.canonize!(g::AbstractGraph, ::AlgNautyGraphs)
53+
ng = is_directed(g) ? NautyDiGraph(g) : NautyGraph(g)
54+
perm = convert(Vector{eltype(g)}, NautyGraphs.canonical_permutation(ng))
55+
permute!(g, perm)
56+
return perm
57+
end
58+
59+
function Graphs.Experimental.count_induced_subgraphisomorph(
60+
g1::AbstractGraph,
61+
g2::AbstractGraph,
62+
::AlgNautyGraphs;
63+
vertex_relation::Union{Nothing,Function}=nothing,
64+
edge_relation::Union{Nothing,Function}=nothing,
65+
)::Int
66+
error(
67+
"Counting induced subgraph isomorphims is currently not supported by `NautyGraphs`. Please use a different isomorphism algorithm.",
68+
)
69+
return nothing
70+
end
71+
72+
function Graphs.Experimental.count_subgraphisomorph(
73+
g1::AbstractGraph,
74+
g2::AbstractGraph,
75+
::AlgNautyGraphs;
76+
vertex_relation::Union{Nothing,Function}=nothing,
77+
edge_relation::Union{Nothing,Function}=nothing,
78+
)::Int
79+
error(
80+
"Counting subgraph isomorphims is currently not supported by `NautyGraphs`. Please use a different isomorphism algorithm.",
81+
)
82+
return nothing
83+
end
84+
85+
function Graphs.Experimental.count_isomorph(
86+
g1::AbstractGraph,
87+
g2::AbstractGraph,
88+
::AlgNautyGraphs;
89+
vertex_relation::Union{Nothing,Function}=nothing,
90+
edge_relation::Union{Nothing,Function}=nothing,
91+
)::Int
92+
error(
93+
"Counting isomorphims is currently not supported by `NautyGraphs`. Please use a different isomorphism algorithm.",
94+
)
95+
return nothing
96+
end
97+
98+
function Graphs.Experimental.all_induced_subgraphisomorph(
99+
g1::AbstractGraph,
100+
g2::AbstractGraph,
101+
::AlgNautyGraphs;
102+
vertex_relation::Union{Nothing,Function}=nothing,
103+
edge_relation::Union{Nothing,Function}=nothing,
104+
)::Channel{Vector{Tuple{eltype(g1),eltype(g2)}}}
105+
error(
106+
"Generating all induced subgraph isomorphims is currently not supported by `NautyGraphs`. Please use a different isomorphism algorithm.",
107+
)
108+
return nothing
109+
end
110+
111+
function Graphs.Experimental.all_subgraphisomorph(
112+
g1::AbstractGraph,
113+
g2::AbstractGraph,
114+
::AlgNautyGraphs;
115+
vertex_relation::Union{Nothing,Function}=nothing,
116+
edge_relation::Union{Nothing,Function}=nothing,
117+
)::Channel{Vector{Tuple{eltype(g1),eltype(g2)}}}
118+
error(
119+
"Generating all subgraph isomorphims is currently not supported by `NautyGraphs`. Please use a different isomorphism algorithm.",
120+
)
121+
return nothing
122+
end
123+
124+
function Graphs.Experimental.all_isomorph(
125+
g1::AbstractGraph,
126+
g2::AbstractGraph,
127+
::AlgNautyGraphs;
128+
vertex_relation::Union{Nothing,Function}=nothing,
129+
edge_relation::Union{Nothing,Function}=nothing,
130+
)::Channel{Vector{Tuple{eltype(g1),eltype(g2)}}}
131+
error(
132+
"Generating all isomorphims is currently not supported by `NautyGraphs`. Please use a different isomorphism algorithm.",
133+
)
134+
return nothing
135+
end
136+
137+
end

src/Experimental/Experimental.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ export description,
77
# isomorphism
88
VF2,
99
vf2,
10+
AlgNautyGraphs,
1011
IsomorphismProblem,
1112
SubGraphIsomorphismProblem,
1213
InducedSubGraphIsomorphismProblem,
1314
could_have_isomorph,
1415
has_isomorph,
1516
all_isomorph,
1617
count_isomorph,
18+
canonize!,
1719
has_induced_subgraphisomorph,
1820
count_induced_subgraphisomorph,
1921
all_induced_subgraphisomorph,
@@ -25,6 +27,7 @@ description() = "This module contains experimental graph functions."
2527

2628
include("isomorphism.jl")
2729
include("vf2.jl") # Julian implementation of VF2 algorithm
30+
include("nautygraphs.jl")
2831
include("Parallel/Parallel.jl")
2932
include("Traversals/Traversals.jl")
3033
include("ShortestPaths/ShortestPaths.jl")

src/Experimental/isomorphism.jl

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,7 @@ function has_induced_subgraphisomorph(
8787
vertex_relation::Union{Nothing,Function}=nothing,
8888
edge_relation::Union{Nothing,Function}=nothing,
8989
)::Bool
90-
return has_induced_subgraphisomorph(
91-
g1, g2, alg; vertex_relation=vertex_relation, edge_relation=edge_relation
92-
)
90+
throw(MethodError(has_induced_subgraphisomorph, (g1, g2, alg)))
9391
end
9492

9593
"""
@@ -130,9 +128,7 @@ function has_subgraphisomorph(
130128
vertex_relation::Union{Nothing,Function}=nothing,
131129
edge_relation::Union{Nothing,Function}=nothing,
132130
)::Bool
133-
return has_subgraphisomorph(
134-
g1, g2, alg; vertex_relation=vertex_relation, edge_relation=edge_relation
135-
)
131+
throw(MethodError(has_subgraphisomorph, (g1, g2, alg)))
136132
end
137133

138134
"""
@@ -141,12 +137,14 @@ end
141137
Return `true` if the graph `g1` is isomorphic to `g2`.
142138
143139
### Optional Arguments
144-
- `alg`: The algorithm that is used to find the induced subgraph isomorphism. Can be only
145-
`VF2()` at the moment.
140+
- `alg`: The algorithm that is used to find the induced subgraph isomorphism. Can be
141+
`VF2()` or `AlgNautyGraphs()`, if `NautyGraphs` is installed and imported.
146142
- `vertex_relation`: A binary function that takes a vertex from `g1` and one from `g2`. An
147-
isomorphism only exists if this function returns `true` for all matched vertices.
143+
isomorphism only exists if this function returns `true` for all matched vertices. Only
144+
works with `VF2()` at the moment.
148145
- `edge_relation`: A binary function that takes an edge from `g1` and one from `g2`. An
149-
isomorphism only exists if this function returns `true` for all matched edges.
146+
isomorphism only exists if this function returns `true` for all matched edges. Only
147+
works with `VF2()` at the moment.
150148
151149
### Examples
152150
```doctest.jl
@@ -173,9 +171,40 @@ function has_isomorph(
173171
vertex_relation::Union{Nothing,Function}=nothing,
174172
edge_relation::Union{Nothing,Function}=nothing,
175173
)::Bool
176-
return has_isomorph(
177-
g1, g2, alg; vertex_relation=vertex_relation, edge_relation=edge_relation
178-
)
174+
throw(MethodError(has_isomorph, (g1, g2, alg)))
175+
end
176+
177+
"""
178+
canonize!(g, alg::IsomorphismAlgorithm=AlgNautyGraphs())
179+
180+
Permute the vertices of graph `g` into the canonical order defined by the algorithm `alg` and return the permutation.
181+
If graphs `g1` and `g2` are isomorphic, the orders of their vertices will be equal after canonizing them with the same algorithm.
182+
183+
### Optional Arguments
184+
- `alg`: The algorithm that is used to canonize the graph. Can be only be `AlgNautyGraphs()`
185+
at this moment, which requires `NautyGraphs` to be installed and imported.
186+
187+
### Examples
188+
```doctest.jl
189+
julia> canonize!(path_graph(3))
190+
[1, 3, 2]
191+
192+
julia> g1 = path_digraph(4)
193+
julia> g2 = path_digraph(4)[[2, 3, 1, 4]]
194+
julia> g1 == g2
195+
false
196+
julia> canonize!(g1)
197+
[4, 2, 3, 1]
198+
julia> canonize!(g2)
199+
[4, 1, 2, 3]
200+
julia> g1 == g2
201+
true
202+
```
203+
### See also
204+
[`has_isomorph`](@ref)
205+
"""
206+
function canonize!(g::AbstractGraph, alg::IsomorphismAlgorithm=AlgNautyGraphs())
207+
throw(MethodError(canonize!, (g, alg)))
179208
end
180209

181210
"""
@@ -214,9 +243,7 @@ function count_induced_subgraphisomorph(
214243
vertex_relation::Union{Nothing,Function}=nothing,
215244
edge_relation::Union{Nothing,Function}=nothing,
216245
)::Int
217-
return count_induced_subgraphisomorph(
218-
g1, g2, alg; vertex_relation=vertex_relation, edge_relation=edge_relation
219-
)
246+
throw(MethodError(count_induced_subgraphisomorph, (g1, g2, alg)))
220247
end
221248

222249
"""
@@ -257,13 +284,7 @@ function count_subgraphisomorph(
257284
vertex_relation::Union{Nothing,Function}=nothing,
258285
edge_relation::Union{Nothing,Function}=nothing,
259286
)::Int
260-
return count_subgraphisomorph(
261-
g1::AbstractGraph,
262-
g2::AbstractGraph,
263-
VF2();
264-
vertex_relation=vertex_relation,
265-
edge_relation=edge_relation,
266-
)
287+
throw(MethodError(count_subgraphisomorph, (g1, g2, alg)))
267288
end
268289

269290
"""
@@ -304,9 +325,7 @@ function count_isomorph(
304325
vertex_relation::Union{Nothing,Function}=nothing,
305326
edge_relation::Union{Nothing,Function}=nothing,
306327
)::Int
307-
return count_isomorph(
308-
g1, g2, alg; vertex_relation=vertex_relation, edge_relation=edge_relation
309-
)
328+
throw(MethodError(count_isomorph, (g1, g2, alg)))
310329
end
311330

312331
"""
@@ -353,9 +372,7 @@ function all_induced_subgraphisomorph(
353372
vertex_relation::Union{Nothing,Function}=nothing,
354373
edge_relation::Union{Nothing,Function}=nothing,
355374
)::Channel{Vector{Tuple{eltype(g1),eltype(g2)}}}
356-
return all_induced_subgraphisomorph(
357-
g1, g2, alg; vertex_relation=vertex_relation, edge_relation=edge_relation
358-
)
375+
throw(MethodError(all_induced_subgraphisomorph, (g1, g2, alg)))
359376
end
360377

361378
"""
@@ -404,9 +421,7 @@ function all_subgraphisomorph(
404421
vertex_relation::Union{Nothing,Function}=nothing,
405422
edge_relation::Union{Nothing,Function}=nothing,
406423
)::Channel{Vector{Tuple{eltype(g1),eltype(g2)}}}
407-
return all_subgraphisomorph(
408-
g1, g2, alg; vertex_relation=vertex_relation, edge_relation=edge_relation
409-
)
424+
throw(MethodError(all_subgraphisomorph, (g1, g2, alg)))
410425
end
411426

412427
"""
@@ -458,7 +473,5 @@ function all_isomorph(
458473
vertex_relation::Union{Nothing,Function}=nothing,
459474
edge_relation::Union{Nothing,Function}=nothing,
460475
)::Channel{Vector{Tuple{eltype(g1),eltype(g2)}}}
461-
return all_isomorph(
462-
g1, g2, alg; vertex_relation=vertex_relation, edge_relation=edge_relation
463-
)
476+
throw(MethodError(all_isomorph, (g1, g2, alg)))
464477
end

src/Experimental/nautygraphs.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
"""
2+
AlgNautyGraphs
3+
4+
An empty concrete type used to dispatch to [`NautyGraphs`](@ref) isomorphism functions.
5+
"""
6+
struct AlgNautyGraphs <: IsomorphismAlgorithm end
7+
8+
# The implementation of NautyGraph methods for graph isomorphism is done as a package extension in /ext/NautyGraphsExt.jl

0 commit comments

Comments
 (0)