From 85f69d653065de5a60fe7cb93f06ee9ddd4940e1 Mon Sep 17 00:00:00 2001 From: Seth Bromberger Date: Sun, 25 Mar 2018 09:03:14 -0700 Subject: [PATCH] fixes #33 --- src/MetaGraphs.jl | 56 ++++++++++++------------ test/metagraphs.jl | 104 +++++++++++++++++++++++++-------------------- 2 files changed, 88 insertions(+), 72 deletions(-) diff --git a/src/MetaGraphs.jl b/src/MetaGraphs.jl index 27c231f..c41d7aa 100644 --- a/src/MetaGraphs.jl +++ b/src/MetaGraphs.jl @@ -71,7 +71,7 @@ has_vertex(g::AbstractMetaGraph, x...) = has_vertex(g.graph, x...) inneighbors(g::AbstractMetaGraph, v::Integer) = inneighbors(g.graph, v) outneighbors(g::AbstractMetaGraph, v::Integer) = fadj(g.graph, v) -issubset(g::T, h::T) where T<:AbstractMetaGraph = issubset(g.graph, h.graph) +issubset(g::T, h::T) where T <: AbstractMetaGraph = issubset(g.graph, h.graph) """ add_edge!(g, u, v, s, val) @@ -113,7 +113,7 @@ end return true if the vertex has been added, false otherwise. """ add_vertex!(g::AbstractMetaGraph) = add_vertex!(g.graph) -function add_vertex!(g::AbstractMetaGraph,d::Dict) +function add_vertex!(g::AbstractMetaGraph, d::Dict) add_vertex!(g) || return false set_props!(g, nv(g), d) return true @@ -140,28 +140,30 @@ function rem_vertex!(g::AbstractMetaGraph, v::Integer) for n in inneighbors(g, lastv) clear_props!(g, n, lastv) end - - for n in outneighbors(g, v) - clear_props!(g, v, n) - end - - for n in inneighbors(g, v) - clear_props!(g, n, v) + if v != lastv # ignore if we're removing the last vertex. + for n in outneighbors(g, v) + clear_props!(g, v, n) + end + for n in inneighbors(g, v) + clear_props!(g, n, v) + end end clear_props!(g, lastv) retval = rem_vertex!(g.graph, v) retval && set_props!(g, v, lastvprops) - for n in outneighbors(g, v) - set_props!(g, v, n, lasteoutprops[n]) - end - - for n in inneighbors(g, v) - set_props!(g, n, v, lasteinprops[n]) + if v != lastv # ignore if we're removing the last vertex. + for n in outneighbors(g, v) + set_props!(g, v, n, lasteoutprops[n]) + end + + for n in inneighbors(g, v) + set_props!(g, n, v, lasteinprops[n]) + end end return retval end -struct MetaWeights{T<:Integer,U<:Real} <: AbstractMatrix{U} +struct MetaWeights{T <: Integer,U <: Real} <: AbstractMatrix{U} n::T weightfield::Symbol defaultweight::U @@ -192,7 +194,7 @@ end function getindex(g::AbstractMetaGraph, indx::Integer, prop::Symbol) haskey(g.metaindex, prop) || error("':$prop' is not an index") - return props(g,indx)[prop] + return props(g, indx)[prop] end size(d::MetaWeights) = (d.n, d.n) @@ -286,10 +288,10 @@ Will return false if vertex or edge does not exist, true otherwise set_prop!(g::AbstractMetaGraph, prop::Symbol, val) = set_props!(g, Dict(prop => val)) set_prop!(g::AbstractMetaGraph, v::Integer, prop::Symbol, val) = if in(prop, g.indices) - error("':$prop' is an indexing property, use `set_indexing_prop!()` instead") - else - set_props!(g, v, Dict(prop => val)) - end + error("':$prop' is an indexing property, use `set_indexing_prop!()` instead") +else + set_props!(g, v, Dict(prop => val)) +end set_prop!(g::AbstractMetaGraph, e::SimpleEdge, prop::Symbol, val) = set_props!(g, e, Dict(prop => val)) set_prop!(g::AbstractMetaGraph{T}, u::Integer, v::Integer, prop::Symbol, val) where T = set_prop!(g, Edge(T(u), T(v)), prop, val) @@ -316,10 +318,10 @@ rem_prop!(g::AbstractMetaGraph{T}, u::Integer, v::Integer, prop::Symbol) where T Provides a default index value for a vertex if no value currently exists. The default is a string: "\$prop\$i" where `prop` is the property name and `i` is the vertex number. If some other vertex already has this name, a randomized string is generated (though the way it is generated is deterministic). """ -function default_index_value(v::Integer, prop::Symbol, index_values::Set{Any}; exclude=nothing) +function default_index_value(v::Integer, prop::Symbol, index_values::Set{Any}; exclude = nothing) val = string(prop) * string(v) if in(val, index_values) || val == exclude - srand(v+hash(prop)) + srand(v + hash(prop)) val = randstring() warn("'$(string(prop))$v' is already in index, setting ':$prop' for vertex $v to $val") end @@ -335,16 +337,16 @@ are already set, each vertex must have unique values. Optionally, set the index `val` for vertex `v`. Any vertices without values will be set to a default ("(prop)(v)"). """ -function set_indexing_prop!(g::AbstractMetaGraph, prop::Symbol; exclude=nothing) +function set_indexing_prop!(g::AbstractMetaGraph, prop::Symbol; exclude = nothing) in(prop, g.indices) && return g.indices index_values = [g.vprops[v][prop] for v in keys(g.vprops) if haskey(g.vprops[v], prop)] length(index_values) != length(union(index_values)) && error("Cannot make $prop an index, duplicate values detected") index_values = Set(index_values) - g.metaindex[prop] = Dict{Any, Integer}() + g.metaindex[prop] = Dict{Any,Integer}() for v in 1:size(g)[1] if !haskey(g.vprops, v) || !haskey(g.vprops[v], prop) - val = default_index_value(v, prop, index_values, exclude=exclude) + val = default_index_value(v, prop, index_values, exclude = exclude) set_prop!(g, v, prop, val) end g.metaindex[prop][g.vprops[v][prop]] = v @@ -354,7 +356,7 @@ function set_indexing_prop!(g::AbstractMetaGraph, prop::Symbol; exclude=nothing) end function set_indexing_prop!(g::AbstractMetaGraph, v::Integer, prop::Symbol, val::Any) - !in(prop, g.indices) && set_indexing_prop!(g, prop, exclude=val) + !in(prop, g.indices) && set_indexing_prop!(g, prop, exclude = val) (haskey(g.metaindex[prop], val) && g.vprops[v][prop] == val) && return g.indices haskey(g.metaindex[prop], val) && error("':$prop' index already contains $val") diff --git a/test/metagraphs.jl b/test/metagraphs.jl index cb9085b..083ee0e 100644 --- a/test/metagraphs.jl +++ b/test/metagraphs.jl @@ -16,18 +16,18 @@ importall MetaGraphs dgx = PathDiGraph(4) mg = MetaGraph() - @test add_vertex!(mg,:color,"red") && get_prop(mg,nv(mg),:color) == "red" - @test add_vertex!(mg,Dict(:color=>"red",:prop2=>"prop2")) && props(mg,nv(mg)) == Dict(:color=>"red",:prop2=>"prop2") - @test add_edge!(mg,1,2,:color,"blue") && get_prop(mg,1,2,:color) == "blue" - @test add_vertex!(mg) && add_edge!(mg,1,3,Dict(:color => "red",:prop2 => "prop2")) && props(mg,1,3) == Dict(:color=>"red",:prop2=>"prop2") + @test add_vertex!(mg, :color, "red") && get_prop(mg, nv(mg), :color) == "red" + @test add_vertex!(mg, Dict(:color => "red", :prop2 => "prop2")) && props(mg, nv(mg)) == Dict(:color => "red", :prop2 => "prop2") + @test add_edge!(mg, 1, 2, :color, "blue") && get_prop(mg, 1, 2, :color) == "blue" + @test add_vertex!(mg) && add_edge!(mg, 1, 3, Dict(:color => "red", :prop2 => "prop2")) && props(mg, 1, 3) == Dict(:color => "red", :prop2 => "prop2") for g in testgraphs(gx) mg = MetaGraph(g) g2 = SimpleGraph(mg) @test g2 == mg.graph - @test eltype(@inferred(MetaGraph{UInt8, Float16}(mg))) == UInt8 - @test weighttype(@inferred(MetaGraph{UInt8, Float16}(mg))) == Float16 + @test eltype(@inferred(MetaGraph{UInt8,Float16}(mg))) == UInt8 + @test weighttype(@inferred(MetaGraph{UInt8,Float16}(mg))) == Float16 @test @inferred(MetaGraphs.fadj(mg, 2)) == LightGraphs.SimpleGraphs.fadj(g, 2) @test @inferred(MetaGraphs.badj(mg, 2)) == LightGraphs.SimpleGraphs.badj(g, 2) @@ -38,22 +38,22 @@ importall MetaGraphs @test @inferred(eltype(MetaGraph(g, 2.0))) == eltype(g) @test @inferred(eltype(MetaGraph(g, :cost))) == eltype(g) @test @inferred(eltype(MetaGraph(g, :cost, 2.0))) == eltype(g) - @test @inferred(eltype(MetaGraph{UInt8, Float16}(g))) == UInt8 - @test @inferred(eltype(MetaGraph{UInt8, Float16}(g, :cost))) == UInt8 - @test @inferred(eltype(MetaGraph{UInt8, Float16}(g, 4))) == UInt8 + @test @inferred(eltype(MetaGraph{UInt8,Float16}(g))) == UInt8 + @test @inferred(eltype(MetaGraph{UInt8,Float16}(g, :cost))) == UInt8 + @test @inferred(eltype(MetaGraph{UInt8,Float16}(g, 4))) == UInt8 @test @inferred(ne(mg)) == 3 @test @inferred(nv(mg)) == 4 @test @inferred(!is_directed(mg)) @test @inferred(vertices(mg)) == 1:4 - @test Edge(2,3) in edges(mg) - @test @inferred(outneighbors(mg,2)) == inneighbors(mg,2) == neighbors(mg,2) + @test Edge(2, 3) in edges(mg) + @test @inferred(outneighbors(mg, 2)) == inneighbors(mg, 2) == neighbors(mg, 2) @test @inferred(has_edge(mg, 2, 3)) @test @inferred(has_edge(mg, 3, 2)) mgc = copy(mg) - @test @inferred(add_edge!(mgc, 4=>1)) && mgc == MetaGraph(CycleGraph(4)) - @test @inferred(has_edge(mgc, 4=>1)) && has_edge(mgc, 0x04=>0x01) + @test @inferred(add_edge!(mgc, 4 => 1)) && mgc == MetaGraph(CycleGraph(4)) + @test @inferred(has_edge(mgc, 4 => 1)) && has_edge(mgc, 0x04 => 0x01) mgc = copy(mg) @test @inferred(add_edge!(mgc, (4, 1))) && mgc == MetaGraph(CycleGraph(4)) @test @inferred(has_edge(mgc, (4, 1))) && has_edge(mgc, (0x04, 0x01)) @@ -69,11 +69,11 @@ importall MetaGraphs @test @inferred(rem_vertex!(mga, 2)) && ne(mga) == 1 @test @inferred(!rem_vertex!(mga, 10)) - @test @inferred(zero(mg)) == MetaGraph{eltype(mg), weighttype(mg)}() + @test @inferred(zero(mg)) == MetaGraph{eltype(mg),weighttype(mg)}() @test @inferred(eltype(mg)) == eltype(outneighbors(mg, 1)) == eltype(nv(mg)) T = @inferred(eltype(mg)) U = @inferred(weighttype(mg)) - @test @inferred(nv(MetaGraph{T, U}(6))) == 6 + @test @inferred(nv(MetaGraph{T,U}(6))) == 6 end @@ -82,8 +82,8 @@ importall MetaGraphs g2 = SimpleDiGraph(mg) @test g2 == mg.graph - @test eltype(@inferred(MetaDiGraph{UInt8, Float16}(mg))) == UInt8 - @test weighttype(@inferred(MetaDiGraph{UInt8, Float16}(mg))) == Float16 + @test eltype(@inferred(MetaDiGraph{UInt8,Float16}(mg))) == UInt8 + @test weighttype(@inferred(MetaDiGraph{UInt8,Float16}(mg))) == Float16 @test @inferred(MetaGraphs.fadj(mg, 2)) == LightGraphs.SimpleGraphs.fadj(g, 2) @test @inferred(MetaGraphs.badj(mg, 2)) == LightGraphs.SimpleGraphs.badj(g, 2) @@ -94,24 +94,24 @@ importall MetaGraphs @test @inferred(eltype(MetaDiGraph(g, 2.0))) == eltype(g) @test @inferred(eltype(MetaDiGraph(g, :cost))) == eltype(g) @test @inferred(eltype(MetaDiGraph(g, :cost, 2.0))) == eltype(g) - @test @inferred(eltype(MetaDiGraph{UInt8, Float16}(g))) == UInt8 - @test @inferred(eltype(MetaDiGraph{UInt8, Float16}(g, :cost))) == UInt8 - @test @inferred(eltype(MetaDiGraph{UInt8, Float16}(g, 4))) == UInt8 + @test @inferred(eltype(MetaDiGraph{UInt8,Float16}(g))) == UInt8 + @test @inferred(eltype(MetaDiGraph{UInt8,Float16}(g, :cost))) == UInt8 + @test @inferred(eltype(MetaDiGraph{UInt8,Float16}(g, 4))) == UInt8 @test @inferred(ne(mg)) == 3 @test @inferred(nv(mg)) == 4 @test @inferred(is_directed(mg)) @test @inferred(vertices(mg)) == 1:4 - @test Edge(2,3) in edges(mg) - @test @inferred(outneighbors(mg,2)) == [3] - @test @inferred(inneighbors(mg,2)) == [1] + @test Edge(2, 3) in edges(mg) + @test @inferred(outneighbors(mg, 2)) == [3] + @test @inferred(inneighbors(mg, 2)) == [1] @test @inferred(has_edge(mg, 2, 3)) @test @inferred(!has_edge(mg, 3, 2)) mgc = copy(mg) - @test @inferred(add_edge!(mgc, 4=>1)) && mgc == MetaDiGraph(CycleDiGraph(4)) - @test @inferred(has_edge(mgc, 4=>1)) && has_edge(mgc, 0x04=>0x01) + @test @inferred(add_edge!(mgc, 4 => 1)) && mgc == MetaDiGraph(CycleDiGraph(4)) + @test @inferred(has_edge(mgc, 4 => 1)) && has_edge(mgc, 0x04 => 0x01) mgc = copy(mg) @test @inferred(add_edge!(mgc, (4, 1))) && mgc == MetaDiGraph(CycleDiGraph(4)) @test @inferred(has_edge(mgc, (4, 1))) && has_edge(mgc, (0x04, 0x01)) @@ -127,11 +127,11 @@ importall MetaGraphs @test @inferred(rem_vertex!(mga, 2)) && ne(mga) == 1 @test @inferred(!rem_vertex!(mga, 10)) - @test @inferred(zero(mg)) == MetaDiGraph{eltype(mg), weighttype(mg)}() + @test @inferred(zero(mg)) == MetaDiGraph{eltype(mg),weighttype(mg)}() @test @inferred(eltype(mg)) == eltype(outneighbors(mg, 1)) == eltype(nv(mg)) T = @inferred(eltype(mg)) U = @inferred(weighttype(mg)) - @test @inferred(nv(MetaDiGraph{T, U}(6))) == 6 + @test @inferred(nv(MetaDiGraph{T,U}(6))) == 6 end for gbig in [SimpleGraph(0xff), SimpleDiGraph(0xff)] @@ -161,13 +161,13 @@ importall MetaGraphs mg = MetaGraph(CompleteGraph(3), 3.0) @test enumerate_paths(dijkstra_shortest_paths(mg, 1), 3) == [1, 3] - @test typeof(set_prop!(mg, 1, 2, :weight, 0.2)) == Dict{Symbol, Float64} - @test typeof(set_prop!(mg, 2, 3, :weight, 1)) == Dict{Symbol, Int64} + @test typeof(set_prop!(mg, 1, 2, :weight, 0.2)) == Dict{Symbol,Float64} + @test typeof(set_prop!(mg, 2, 3, :weight, 1)) == Dict{Symbol,Int64} @test enumerate_paths(dijkstra_shortest_paths(mg, 1), 3) == [1, 2, 3] - @test typeof(set_prop!(mg, 1, :color, "blue")) == Dict{Symbol, String} - @test typeof(set_prop!(mg, 1, :id, 0x5)) == Dict{Symbol, Any} - @test typeof(set_prop!(mg, :name, "test graph")) == Dict{Symbol, Any} + @test typeof(set_prop!(mg, 1, :color, "blue")) == Dict{Symbol,String} + @test typeof(set_prop!(mg, 1, :id, 0x5)) == Dict{Symbol,Any} + @test typeof(set_prop!(mg, :name, "test graph")) == Dict{Symbol,Any} @test length(props(mg)) == 1 @@ -198,13 +198,13 @@ importall MetaGraphs mg = MetaDiGraph(PathDiGraph(3), 3.0) add_edge!(mg, 1, 3) @test enumerate_paths(dijkstra_shortest_paths(mg, 1), 3) == [1, 3] - @test typeof(set_prop!(mg, 1, 2, :weight, 0.2)) == Dict{Symbol, Float64} - @test typeof(set_prop!(mg, 2, 3, :weight, 1)) == Dict{Symbol, Int64} + @test typeof(set_prop!(mg, 1, 2, :weight, 0.2)) == Dict{Symbol,Float64} + @test typeof(set_prop!(mg, 2, 3, :weight, 1)) == Dict{Symbol,Int64} @test enumerate_paths(dijkstra_shortest_paths(mg, 1), 3) == [1, 2, 3] - @test typeof(set_prop!(mg, 1, :color, "blue")) == Dict{Symbol, String} - @test typeof(set_prop!(mg, 1, :id, 0x5)) == Dict{Symbol, Any} - @test typeof(set_prop!(mg, :name, "test graph")) == Dict{Symbol, Any} + @test typeof(set_prop!(mg, 1, :color, "blue")) == Dict{Symbol,String} + @test typeof(set_prop!(mg, 1, :id, 0x5)) == Dict{Symbol,Any} + @test typeof(set_prop!(mg, :name, "test graph")) == Dict{Symbol,Any} @test length(props(mg)) == 1 @@ -249,10 +249,10 @@ importall MetaGraphs @test weightfield!(mg, :weight) == :weight @test enumerate_paths(dijkstra_shortest_paths(mg, 1), 3) == [1, 2, 3] - @test length(set_props!(mg, 1, 2, Dict(:color=>:blue, :action=>"knows"))) == 3 + @test length(set_props!(mg, 1, 2, Dict(:color => :blue, :action => "knows"))) == 3 @test rem_edge!(mg, 1, 2) @test length(props(mg, 1, 2)) == 0 - @test length(set_props!(mg, Dict(:name=>"testgraph", :type=>"undirected"))) == 2 + @test length(set_props!(mg, Dict(:name => "testgraph", :type => "undirected"))) == 2 mg = MetaGraph(CompleteGraph(3), 3.0) set_prop!(mg, 1, :color, "blue") @@ -327,6 +327,19 @@ importall MetaGraphs @test length(mga.eprops) == 1 # should only be edge 3=>2 @test props(mga, 3, 2)[:name] == "3, 4" + # test for #33 + mga = MetaGraph(PathGraph(4)) + set_prop!(mga, 1, 2, :name, "1, 2") + set_prop!(mga, 2, 3, :name, "2, 3") + set_prop!(mga, 3, 4, :name, "3, 4") + set_prop!(mga, 3, :v, 3) + set_prop!(mga, 4, :v, 4) + @test rem_vertex!(mga, nv(mga)) + @test has_prop(mga, 2, 3, :name) + @test !has_prop(mga, 3, 4, :name) + @test !has_prop(mga, 4, :v) + @test has_prop(mga, 3, :v) + @@ -342,8 +355,8 @@ end end for i in 1:100 - set_prop!(G, i, :not_unique, "$(i%5)") - set_prop!(dG, i, :not_unique, "$(i%5)") + set_prop!(G, i, :not_unique, "$(i % 5)") + set_prop!(dG, i, :not_unique, "$(i % 5)") end @test set_indexing_prop!(G, :name) == Set{Symbol}([:name]) @@ -358,9 +371,10 @@ end @test_throws ErrorException set_indexing_prop!(dG, 4, :name, "dgnode_3") @test_throws ErrorException set_prop!(G, 3, :name, "name3") @test_throws ErrorException set_prop!(dG, 3, :name, "name3") - @test_throws ErrorException set_props!(G, 5, Dict(:name=>"name", :other_name=>"something")) - @test_throws ErrorException set_props!(dG, 5, Dict(:name=>"name", :other_name=>"something")) + @test_throws ErrorException set_props!(G, 5, Dict(:name => "name", :other_name => "something")) + @test_throws ErrorException set_props!(dG, 5, Dict(:name => "name", :other_name => "something")) + info("Ignore \"'foo1' is already in index\" warnings") set_indexing_prop!(G, 50, :name, "another name") set_indexing_prop!(G, 50, :name, "another name") @@ -376,8 +390,8 @@ end @test G[12, :foo] == "foo12" @test G["bar", :foo] == 42 @test G[42, :foo] == "bar" - @test isa(G[:foo], Dict{Any, Integer}) - @test isa(dG[:foo], Dict{Any, Integer}) + @test isa(G[:foo], Dict{Any,Integer}) + @test isa(dG[:foo], Dict{Any,Integer}) @test dG["foo30", :foo] == 30