From 0f7db62411822d68aebeefa0b708f546e54308f9 Mon Sep 17 00:00:00 2001 From: Marco Cognetta Date: Sun, 2 Oct 2022 18:26:00 +0900 Subject: [PATCH 1/3] add mycielski operator --- src/Graphs.jl | 1 + src/operators.jl | 73 +++++++++++++++++++++++++++++++++++++++++++++++ test/operators.jl | 16 +++++++++++ 3 files changed, 90 insertions(+) diff --git a/src/Graphs.jl b/src/Graphs.jl index bbddf395d..976b62ce5 100644 --- a/src/Graphs.jl +++ b/src/Graphs.jl @@ -55,6 +55,7 @@ complement, reverse, reverse!, blockdiag, union, intersect, difference, symmetric_difference, join, tensor_product, cartesian_product, crosspath, induced_subgraph, egonet, merge_vertices!, merge_vertices, +mycielski, # bfs gdistances, gdistances!, bfs_tree, bfs_parents, has_path, diff --git a/src/operators.jl b/src/operators.jl index daa597b66..36ac52bee 100644 --- a/src/operators.jl +++ b/src/operators.jl @@ -851,3 +851,76 @@ function merge_vertices!(g::Graph{T}, vs::Vector{U} where U <: Integer) where T return new_vertex_ids end + +""" + mycielski(g) + +Returns a graph after applying the Mycielski operator to the input. The Mycielski operator +returns a new graph with `2n+1` vertices and `3e+n` edges and will increase the chromatic +number of the graph by 1. + +The Mycielski operation can be repeated by using the `iterations` kwarg. Each time, it will +apply the operator to the previous iterations graph. + +For each vertex in the original graph, that vertex and a copy of it is added to the new graph. +Then, for each edge `(x, y)` in the original graph, the edges `(x, y)`, `(x', y)`, and `(x, y')` +are added to the new graph, where `x'` and `y'` are the "copies" of `x` and `y`, respectively. +In otherwords, the original graph is present as a subgraph, and each vertex in the original graph +is connected to all of it's neighbors' copies. Finally, one last vertex `w` is added to the graph +and an edge connecting each copy vertex `x'` to `w` is added. + +See [Mycielskian](https://en.wikipedia.org/wiki/Mycielskian) for more information. + +# Examples +```jldoctest +julia> c = CycleGraph(5) +{5, 5} undirected simple Int64 graph + +julia> m = Graphs.mycielski(c) +{11, 20} undirected simple Int64 graph + +julia> collect(edges(m)) +20-element Vector{Graphs.SimpleGraphs.SimpleEdge{Int64}}: + Edge 1 => 2 + Edge 1 => 5 + Edge 1 => 7 + Edge 1 => 10 + Edge 2 => 3 + Edge 2 => 6 + Edge 2 => 8 + Edge 3 => 4 + Edge 3 => 7 + Edge 3 => 9 + Edge 4 => 5 + Edge 4 => 8 + Edge 4 => 10 + Edge 5 => 6 + Edge 5 => 9 + Edge 6 => 11 + Edge 7 => 11 + Edge 8 => 11 + Edge 9 => 11 + Edge 10 => 11 +``` +""" +@traitfn function mycielski(g::AbstractGraph::(!IsDirected); iterations = 1) + ref = g + out = deepcopy(g) + for _ in 1:iterations + N = nv(g) + add_vertices!(out, N + 1) + w = nv(out) + for e in collect(edges(g)) + x, y = Tuple(e) + add_edge!(out, x, y) + add_edge!(out, x, y+N) + add_edge!(out, x+N, y) + end + + for v in 1:N + add_edge!(out, v+N, w) + end + g = out + end + return out +end diff --git a/test/operators.jl b/test/operators.jl index 891816753..5e3256611 100644 --- a/test/operators.jl +++ b/test/operators.jl @@ -320,4 +320,20 @@ @testset "Length: $g" for g in testgraphs(SimpleGraph(100)) @test length(g) == 10000 end + + + @testset "Mycielski Operator" begin + g = complete_graph(2) + + m = mycielski(g; iterations = 8) + @test nv(m) == 767 + @test ne(m) == 22196 + + # check that mycielski preserves triangle-freeness + g = complete_bipartite_graph(10, 5) + m = mycielski(g) + @test nv(m) == 2*15 + 1 + @test ne(m) == 3*50 + 15 + @test all(iszero, triangles(m)) + end end From e1cc60ae1b38ba28b5c1b3447ec74c229481f75e Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 3 Oct 2022 13:50:55 +0900 Subject: [PATCH 2/3] grammar --- src/operators.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/operators.jl b/src/operators.jl index 36ac52bee..18ff7b424 100644 --- a/src/operators.jl +++ b/src/operators.jl @@ -862,11 +862,11 @@ number of the graph by 1. The Mycielski operation can be repeated by using the `iterations` kwarg. Each time, it will apply the operator to the previous iterations graph. -For each vertex in the original graph, that vertex and a copy of it is added to the new graph. +For each vertex in the original graph, that vertex and a copy of it are added to the new graph. Then, for each edge `(x, y)` in the original graph, the edges `(x, y)`, `(x', y)`, and `(x, y')` are added to the new graph, where `x'` and `y'` are the "copies" of `x` and `y`, respectively. -In otherwords, the original graph is present as a subgraph, and each vertex in the original graph -is connected to all of it's neighbors' copies. Finally, one last vertex `w` is added to the graph +In other words, the original graph is present as a subgraph, and each vertex in the original graph +is connected to all of its neighbors' copies. Finally, one last vertex `w` is added to the graph and an edge connecting each copy vertex `x'` to `w` is added. See [Mycielskian](https://en.wikipedia.org/wiki/Mycielskian) for more information. From fa6c65da67930abafeb9668d7373fb9a273d4be6 Mon Sep 17 00:00:00 2001 From: Marco Cognetta Date: Wed, 5 Oct 2022 21:36:42 +0900 Subject: [PATCH 3/3] comments from review --- src/operators.jl | 10 ++++------ test/operators.jl | 8 ++++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/operators.jl b/src/operators.jl index 18ff7b424..56ca704ec 100644 --- a/src/operators.jl +++ b/src/operators.jl @@ -904,15 +904,14 @@ julia> collect(edges(m)) ``` """ @traitfn function mycielski(g::AbstractGraph::(!IsDirected); iterations = 1) - ref = g out = deepcopy(g) for _ in 1:iterations - N = nv(g) + N = nv(out) add_vertices!(out, N + 1) w = nv(out) - for e in collect(edges(g)) - x, y = Tuple(e) - add_edge!(out, x, y) + for e in collect(edges(out)) + x=e.src + y=e.dst add_edge!(out, x, y+N) add_edge!(out, x+N, y) end @@ -920,7 +919,6 @@ julia> collect(edges(m)) for v in 1:N add_edge!(out, v+N, w) end - g = out end return out end diff --git a/test/operators.jl b/test/operators.jl index 5e3256611..6969c7461 100644 --- a/test/operators.jl +++ b/test/operators.jl @@ -329,11 +329,19 @@ @test nv(m) == 767 @test ne(m) == 22196 + # ensure it is not done in-place + @test nv(g) == 2 + @test ne(g) == 1 + # check that mycielski preserves triangle-freeness g = complete_bipartite_graph(10, 5) m = mycielski(g) @test nv(m) == 2*15 + 1 @test ne(m) == 3*50 + 15 @test all(iszero, triangles(m)) + + # ensure it is not done in-place + @test nv(g) == 15 + @test ne(g) == 50 end end