-
Notifications
You must be signed in to change notification settings - Fork 122
Add mycielski operator
#177
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -170,6 +170,8 @@ export | |
| egonet, | ||
| merge_vertices!, | ||
| merge_vertices, | ||
| mycielski!, | ||
| mycielski, | ||
|
|
||
| # bfs | ||
| gdistances, | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -1105,3 +1105,101 @@ function merge_vertices!(g::Graph{T}, vs::Vector{U} where {U<:Integer}) where {T | |||||
|
|
||||||
| return new_vertex_ids | ||||||
| end | ||||||
|
|
||||||
| """ | ||||||
| mycielski!(g; iterations = 1) | ||||||
|
|
||||||
| Performs the mycielski operation on an input graph, in place, for a given number of iterations. | ||||||
| See [`mycielski`](@ref) for the details of the operation. | ||||||
|
|
||||||
| ### Implementation Notes | ||||||
| Operates in place and expects `g` to not have self loops. | ||||||
| """ | ||||||
| function mycielski!(g::SimpleGraph; iterations::Integer=1) | ||||||
| has_self_loops(g) && return g | ||||||
|
|
||||||
| for _ in Base.OneTo(iterations) | ||||||
| N = nv(g) | ||||||
|
|
||||||
| add_vertices!(g, N + 1) | ||||||
| w = nv(g) | ||||||
|
|
||||||
| for u in Base.OneTo(N) | ||||||
| for v in neighbors(g, u) | ||||||
| if v <= N && u < v | ||||||
| add_edge!(g, u, v + N) | ||||||
| add_edge!(g, v, u + N) | ||||||
| end | ||||||
| end | ||||||
| end | ||||||
|
|
||||||
| for v in 1:N | ||||||
| add_edge!(g, v + N, w) | ||||||
| end | ||||||
| end | ||||||
| return g | ||||||
| end | ||||||
|
|
||||||
| """ | ||||||
| mycielski(g; iterations = 1) | ||||||
|
|
||||||
| Returns a graph after applying the Mycielski operator to the input for a given number of | ||||||
| iterations. 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. This operation assumes | ||||||
| that there are no self-loops. | ||||||
|
|
||||||
| 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 are added to the new graph. | ||||||
| Then, for each edge `(u, v)` in the original graph, the edges `(u, v)`, `(u', v)`, and `(u, v')` | ||||||
| are added to the new graph, where `u'` and `v'` are the "copies" of `u` and `v`, respectively. | ||||||
| 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 `u'` to `w` is added. | ||||||
|
|
||||||
| See [Mycielskian](https://en.wikipedia.org/wiki/Mycielskian) for more information. | ||||||
|
|
||||||
| ### Implementation Notes | ||||||
| Supports [`SimpleGraph`](@ref) only. Copies the input before calling [`mycielski!`](@ref). | ||||||
|
|
||||||
| If there is a self-loop, we just return the original graph unmodified. | ||||||
|
|
||||||
| # Examples | ||||||
| ```jldoctest | ||||||
| julia> using Graphs | ||||||
|
|
||||||
| julia> g = cycle_graph(5) | ||||||
| {5, 5} undirected simple Int64 graph | ||||||
|
|
||||||
| julia> gm = mycielski(g) | ||||||
| {11, 20} undirected simple Int64 graph | ||||||
|
|
||||||
| julia> collect(edges(gm)) | ||||||
| 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 | ||||||
| ``` | ||||||
| """ | ||||||
| function mycielski(g; iterations=1) | ||||||
| has_self_loops(g) && return g | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is "doing nothing" the right thing for the mycielski operator on graphs with self loops? Or is the operator not defined on graphs with self loops?
Suggested change
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @assert 2^iterations * (nv(g)+1) - 1 < typemax(eltype(g)) "eltype too small (or a good error message)" |
||||||
| mycielski!(copy(g); iterations=iterations) | ||||||
| end | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -369,4 +369,88 @@ | |
| @testset "Length: $(typeof(g))" for g in test_generic_graphs(SimpleGraph(100)) | ||
| @test length(g) == 10000 | ||
| end | ||
|
|
||
| @testset "Mycielski Operator" begin | ||
| @testset "out of place" begin | ||
| g = complete_graph(2) | ||
|
|
||
| m = mycielski(g; iterations=8) | ||
| @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 | ||
|
|
||
| @testset "in place" begin | ||
| g = complete_graph(2) | ||
|
|
||
| m = mycielski!(g; iterations=8) | ||
| @test nv(m) == 767 | ||
| @test ne(m) == 22196 | ||
|
|
||
| # ensure it is done in-place | ||
| @test nv(g) == 767 | ||
| @test ne(g) == 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)) | ||
|
|
||
| # ensure it is not done in-place | ||
| @test nv(g) == 15 | ||
| @test ne(g) == 50 | ||
| end | ||
|
|
||
| @testset "empty" begin | ||
| g = Graph() | ||
|
|
||
| m = mycielski!(g) | ||
| @test nv(m) == 1 | ||
| @test ne(m) == 0 | ||
|
|
||
| # one more iteration | ||
| m = mycielski!(m) | ||
| @test nv(m) == 3 | ||
| @test ne(m) == 1 | ||
| end | ||
|
|
||
| @testset "isolated vertices" begin | ||
| g = Graph() | ||
| add_vertices!(g, 2) | ||
|
|
||
| m = mycielski!(g) | ||
| @test nv(m) == 5 | ||
| @test ne(m) == 2 | ||
| end | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simple test for insufficient eltype could look like: @testset "insufficient eltype" begin
g = complete_graph(UInt8(2))
@test_throws AssertionError mycielski!(g, iterations=10)
end |
||
| @testset "self loop" begin | ||
| g = complete_graph(5) | ||
|
|
||
| # add a self loop | ||
| add_edge!(g, 1, 1) | ||
| n = nv(g) | ||
| e = ne(g) | ||
|
|
||
| # no modification | ||
| m = mycielski(g) | ||
| @test nv(m) == n | ||
| @test ne(m) == e | ||
| end | ||
| end | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These tests are good, but I think we need to cover some additional test cases such as:
|
||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.