Skip to content

Commit 0cf7d6a

Browse files
authored
added default option to get_prop (#41)
* added default option to get_prop * throw error when accessing non existent edge * get_prop with default using get with default
1 parent 42a2f26 commit 0cf7d6a

File tree

3 files changed

+107
-39
lines changed

3 files changed

+107
-39
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ Dict{Symbol,Any} with 2 entries:
7171
julia> get_prop(mg, 2, :name)
7272
"John"
7373

74+
# set a default value to return in case the property does not exist
75+
julia> get_prop(mg, 2, :nonexistent_prop, "default value")
76+
"default value"
77+
7478
# delete a specific property
7579
julia> rem_prop!(mg, 1, :name)
7680
Dict{Symbol,Any} with 1 entry:

src/MetaGraphs.jl

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ has_vertex(g::AbstractMetaGraph, x...) = has_vertex(g.graph, x...)
7474
inneighbors(g::AbstractMetaGraph, v::Integer) = inneighbors(g.graph, v)
7575
outneighbors(g::AbstractMetaGraph, v::Integer) = fadj(g.graph, v)
7676

77-
issubset(g::T, h::T) where T <: AbstractMetaGraph = issubset(g.graph, h.graph)
77+
issubset(g::T, h::T) where {T<:AbstractMetaGraph} = issubset(g.graph, h.graph)
7878

7979
"""
8080
add_edge!(g, u, v, s, val)
@@ -135,10 +135,10 @@ function rem_vertex!(g::AbstractMetaGraph, v::Integer)
135135
lasteoutprops = Dict(n => props(g, lastv, n) for n in outneighbors(g, lastv))
136136
lasteinprops = Dict(n => props(g, n, lastv) for n in inneighbors(g, lastv))
137137
for ind in g.indices
138-
if haskey(props(g,lastv),ind)
138+
if haskey(props(g, lastv), ind)
139139
pop!(g.metaindex[ind], get_prop(g, lastv, ind))
140140
end
141-
if haskey(props(g,v),ind)
141+
if haskey(props(g, v), ind)
142142
v != lastv && pop!(g.metaindex[ind], get_prop(g, v, ind))
143143
end
144144
end
@@ -191,7 +191,7 @@ function rem_vertex!(g::AbstractMetaGraph, v::Integer)
191191
return true
192192
end
193193

194-
struct MetaWeights{T <: Integer,U <: Real} <: AbstractMatrix{U}
194+
struct MetaWeights{T<:Integer,U<:Real} <: AbstractMatrix{U}
195195
n::T
196196
weightfield::Symbol
197197
defaultweight::U
@@ -203,7 +203,7 @@ show(io::IO, z::MIME"text/plain", x::MetaWeights) = show(io, x)
203203

204204
MetaWeights(g::AbstractMetaGraph) = MetaWeights{eltype(g),eltype(g.defaultweight)}(nv(g), g.weightfield, g.defaultweight, g.eprops, is_directed(g))
205205

206-
function getindex(w::MetaWeights{T,U}, u::Integer, v::Integer)::U where T <: Integer where U <: Real
206+
function getindex(w::MetaWeights{T,U}, u::Integer, v::Integer)::U where {T<:Integer} where {U<:Real}
207207
_e = Edge(u, v)
208208
e = !w.directed && !Graphs.is_ordered(_e) ? reverse(_e) : _e
209209
!haskey(w.eprops, e) && return w.defaultweight
@@ -253,20 +253,33 @@ props(g::AbstractMetaGraph, v::Integer) = get(PropDict, g.vprops, v)
253253
props(g::AbstractMetaGraph, u::Integer, v::Integer) = props(g, Edge(u, v))
254254

255255
"""
256-
get_prop(g, prop)
257-
get_prop(g, v, prop)
258-
get_prop(g, e, prop)
259-
get_prop(g, s, d, prop)
256+
get_prop(g, prop::Symbol)
257+
get_prop(g, prop::Symbol, default)
258+
259+
get_prop(g, v, prop::Symbol)
260+
get_prop(g, v, prop::Symbol, default)
261+
262+
get_prop(g, e, prop::Symbol)
263+
get_prop(g, e, prop::Symbol, default)
264+
get_prop(g, s, d, prop::Symbol)
265+
get_prop(g, s, d, prop::Symbol, default)
260266
261267
Return the property `prop` defined for graph `g`, vertex `v`, or edge `e`
262268
(optionally referenced by source vertex `s` and destination vertex `d`).
263-
If property is not defined, return an error.
269+
Use the version with `default`, to return a default value if the property is not defined. Otherwise, it will return an error.
264270
"""
265271
get_prop(g::AbstractMetaGraph, prop::Symbol) = props(g)[prop]
272+
get_prop(g::AbstractMetaGraph, prop::Symbol, default) = get(props(g), prop, default)
273+
266274
get_prop(g::AbstractMetaGraph, v::Integer, prop::Symbol) = props(g, v)[prop]
275+
get_prop(g::AbstractMetaGraph, v::Integer, prop::Symbol, default) = get(props(g, v), prop, default)
276+
267277
get_prop(g::AbstractMetaGraph, e::SimpleEdge, prop::Symbol) = props(g, e)[prop]
278+
get_prop(g::AbstractMetaGraph, e::SimpleEdge, prop::Symbol, default) = get(props(g, e), prop, default)
268279

269280
get_prop(g::AbstractMetaGraph, u::Integer, v::Integer, prop::Symbol) = get_prop(g, Edge(u, v), prop)
281+
get_prop(g::AbstractMetaGraph, u::Integer, v::Integer, prop::Symbol, default) = get_prop(g, Edge(u, v), prop, default)
282+
270283

271284
"""
272285
has_prop(g, prop)
@@ -300,15 +313,15 @@ end
300313

301314
function set_props!(g::AbstractMetaGraph, v::Integer, d::Dict)
302315
if has_vertex(g, v)
303-
for (prop,val) in d
316+
for (prop, val) in d
304317
index_available(g, v, prop, val) || error("':$prop' index already contains $val")
305318
end
306319
if !_hasdict(g, v)
307320
g.vprops[v] = d
308321
else
309322
merge!(g.vprops[v], d)
310323
end
311-
for prop in intersect(keys(d), g.indices)
324+
for prop in intersect(keys(d), g.indices)
312325
g.metaindex[prop][d[prop]] = v
313326
end
314327
return true
@@ -317,7 +330,7 @@ function set_props!(g::AbstractMetaGraph, v::Integer, d::Dict)
317330
end
318331
# set_props!(g::AbstractMetaGraph, e::SimpleEdge, d::Dict) is dependent on directedness.
319332

320-
set_props!(g::AbstractMetaGraph{T}, u::Integer, v::Integer, d::Dict) where T = set_props!(g, Edge(T(u), T(v)), d)
333+
set_props!(g::AbstractMetaGraph{T}, u::Integer, v::Integer, d::Dict) where {T} = set_props!(g, Edge(T(u), T(v)), d)
321334

322335
"""
323336
set_prop!(g, prop, val)
@@ -339,7 +352,7 @@ set_prop!(g::AbstractMetaGraph, v::Integer, prop::Symbol, val) = begin
339352
end
340353
set_prop!(g::AbstractMetaGraph, e::SimpleEdge, prop::Symbol, val) = set_props!(g, e, Dict(prop => val))
341354

342-
set_prop!(g::AbstractMetaGraph{T}, u::Integer, v::Integer, prop::Symbol, val) where T = set_prop!(g, Edge(T(u), T(v)), prop, val)
355+
set_prop!(g::AbstractMetaGraph{T}, u::Integer, v::Integer, prop::Symbol, val) where {T} = set_prop!(g, Edge(T(u), T(v)), prop, val)
343356

344357
"""
345358
rem_prop!(g, prop)
@@ -355,7 +368,7 @@ rem_prop!(g::AbstractMetaGraph, prop::Symbol) = delete!(g.gprops, prop)
355368
rem_prop!(g::AbstractMetaGraph, v::Integer, prop::Symbol) = delete!(g.vprops[v], prop)
356369
rem_prop!(g::AbstractMetaGraph, e::SimpleEdge, prop::Symbol) = delete!(g.eprops[e], prop)
357370

358-
rem_prop!(g::AbstractMetaGraph{T}, u::Integer, v::Integer, prop::Symbol) where T = rem_prop!(g, Edge(T(u), T(v)), prop)
371+
rem_prop!(g::AbstractMetaGraph{T}, u::Integer, v::Integer, prop::Symbol) where {T} = rem_prop!(g, Edge(T(u), T(v)), prop)
359372

360373
"""
361374
default_index_value(v, prop, index_values; exclude=nothing)
@@ -416,7 +429,7 @@ function set_indexing_prop!(g::AbstractMetaGraph, v::Integer, prop::Symbol, val:
416429
haskey(g.metaindex[prop], val) && error("':$prop' index already contains $val")
417430

418431
if !haskey(g.vprops, v)
419-
push!(g.vprops, v=>Dict{Symbol,Any}())
432+
push!(g.vprops, v => Dict{Symbol,Any}())
420433
end
421434
if haskey(g.vprops[v], prop)
422435
delete!(g.metaindex[prop], g.vprops[v][prop])
@@ -438,7 +451,7 @@ clear_props!(g::AbstractMetaGraph, v::Integer) = _hasdict(g, v) && delete!(g.vpr
438451
clear_props!(g::AbstractMetaGraph, e::SimpleEdge) = _hasdict(g, e) && delete!(g.eprops, e)
439452
clear_props!(g::AbstractMetaGraph) = g.gprops = PropDict()
440453

441-
clear_props!(g::AbstractMetaGraph{T}, u::Integer, v::Integer) where T = clear_props!(g, Edge(T(u), T(v)))
454+
clear_props!(g::AbstractMetaGraph{T}, u::Integer, v::Integer) where {T} = clear_props!(g, Edge(T(u), T(v)))
442455

443456
"""
444457
weightfield!(g, prop)
@@ -514,7 +527,7 @@ filter_vertices(g::AbstractMetaGraph, prop::Symbol) =
514527
filter_vertices(g::AbstractMetaGraph, prop::Symbol, val) =
515528
filter_vertices(g, (g, x) -> has_prop(g, x, prop) && get_prop(g, x, prop) == val)
516529

517-
function _copy_props!(oldg::T, newg::T, vmap) where T <: AbstractMetaGraph
530+
function _copy_props!(oldg::T, newg::T, vmap) where {T<:AbstractMetaGraph}
518531
for (newv, oldv) in enumerate(vmap)
519532
p = props(oldg, oldv)
520533
if !isempty(p)
@@ -540,21 +553,21 @@ function _copy_props!(oldg::T, newg::T, vmap) where T <: AbstractMetaGraph
540553
return nothing
541554
end
542555

543-
function induced_subgraph(g::T, v::AbstractVector{U}) where T <: AbstractMetaGraph where U <: Integer
556+
function induced_subgraph(g::T, v::AbstractVector{U}) where {T<:AbstractMetaGraph} where {U<:Integer}
544557
inducedgraph, vmap = induced_subgraph(g.graph, v)
545558
newg = T(inducedgraph)
546559
_copy_props!(g, newg, vmap)
547560
return newg, vmap
548561
end
549562

550-
function induced_subgraph(g::T, v::AbstractVector{U}) where T <: AbstractMetaGraph where U <: SimpleEdge
563+
function induced_subgraph(g::T, v::AbstractVector{U}) where {T<:AbstractMetaGraph} where {U<:SimpleEdge}
551564
inducedgraph, vmap = induced_subgraph(g.graph, v)
552565
newg = T(inducedgraph)
553566
_copy_props!(g, newg, vmap)
554567
return newg, vmap
555568
end
556569

557-
induced_subgraph(g::T, filt::Iterators.Filter) where T <: AbstractMetaGraph =
570+
induced_subgraph(g::T, filt::Iterators.Filter) where {T<:AbstractMetaGraph} =
558571
induced_subgraph(g, collect(filt))
559572

560573
# TODO - would be nice to be able to apply a function to properties. Not sure
@@ -563,7 +576,7 @@ induced_subgraph(g::T, filt::Iterators.Filter) where T <: AbstractMetaGraph =
563576

564577
==(x::AbstractMetaGraph, y::AbstractMetaGraph) = x.graph == y.graph
565578

566-
copy(g::T) where T <: AbstractMetaGraph = deepcopy(g)
579+
copy(g::T) where {T<:AbstractMetaGraph} = deepcopy(g)
567580

568581
include("metadigraph.jl")
569582
include("metagraph.jl")

test/metagraphs.jl

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using MetaGraphs
22
import Graphs: SimpleGraphs
33
import Base64:
4-
stringmime
4+
stringmime
55

66

77
@testset "MetaGraphs" begin
@@ -21,7 +21,7 @@ import Base64:
2121
mg = MetaGraph()
2222
@test add_vertex!(mg, :color, "red") && get_prop(mg, nv(mg), :color) == "red"
2323
@test add_vertex!(mg, Dict(:color => "red", :prop2 => "prop2")) && props(mg, nv(mg)) == Dict(:color => "red", :prop2 => "prop2")
24-
@test add_edge!(mg, 1, 2, :color, "blue") && get_prop(mg, 1, 2, :color) == "blue"
24+
@test add_edge!(mg, 1, 2, :color, "blue") && get_prop(mg, 1, 2, :color) == "blue"
2525
@test add_vertex!(mg) && add_edge!(mg, 1, 3, Dict(:color => "red", :prop2 => "prop2")) && props(mg, 1, 3) == Dict(:color => "red", :prop2 => "prop2")
2626

2727
for g in testgraphs(gx)
@@ -78,6 +78,31 @@ import Base64:
7878
U = @inferred(weighttype(mg))
7979
@test @inferred(nv(MetaGraph{T,U}(6))) == 6
8080

81+
# get_prop with default argument
82+
# vertices
83+
set_prop!(mg, nv(mg), :testprop, "exists")
84+
@test get_prop(mg, nv(mg), :testprop, "nonexistent") == "exists"
85+
@test get_prop(mg, nv(mg), :testprop_nonexist, "nonexistent") == "nonexistent"
86+
@test get_prop(mg, nv(mg) + 100, :testprop_nonexist, "nonexistent") == "nonexistent"
87+
88+
# edges
89+
set_prop!(mg, 1, 2, :testedgeprop, "5 meters")
90+
@test get_prop(mg, 1, 2, :testedgeprop, "0 meters") == "5 meters"
91+
@test get_prop(mg, 1, 2, :testedgeprop_nonexist, "0 meters") == "0 meters"
92+
@test get_prop(mg, 2, 4, :testedgeprop_nonexist, "0 meters") == "0 meters"
93+
@test get_prop(mg, 2, 1, :testedgeprop, "0 meters") == "5 meters"
94+
@test get_prop(mg, 2, 1, :testedgeprop_nonexist, "0 meters") == "0 meters"
95+
96+
@test get_prop(mg, Edge(1, 2), :testedgeprop, "0 meters") == "5 meters"
97+
@test get_prop(mg, Edge(1, 2), :testedgeprop_nonexist, "0 meters") == "0 meters"
98+
@test get_prop(mg, Edge(2, 4), :testedgeprop_nonexist, "0 meters") == "0 meters"
99+
@test get_prop(mg, Edge(2, 1), :testedgeprop, "0 meters") == "5 meters"
100+
@test get_prop(mg, Edge(2, 1), :testedgeprop_nonexist, "0 meters") == "0 meters"
101+
102+
# graph
103+
set_prop!(mg, :testgraphpprop, "linegraph")
104+
@test get_prop(mg, :testgraphpprop, "circlegraph") == "linegraph"
105+
@test get_prop(mg, :testgraphpprop_nonexist, "circlegraph") == "circlegraph"
81106
end
82107

83108
for g in testdigraphs(dgx)
@@ -135,6 +160,32 @@ import Base64:
135160
T = @inferred(eltype(mg))
136161
U = @inferred(weighttype(mg))
137162
@test @inferred(nv(MetaDiGraph{T,U}(6))) == 6
163+
164+
# get_prop with default argument
165+
# vertices
166+
set_prop!(mg, nv(mg), :testprop, "exists")
167+
@test get_prop(mg, nv(mg), :testprop, "nonexistent") == "exists"
168+
@test get_prop(mg, nv(mg), :testprop_nonexist, "nonexistent") == "nonexistent"
169+
@test get_prop(mg, nv(mg) + 100, :testprop_nonexist, "nonexistent") == "nonexistent"
170+
171+
# edges
172+
set_prop!(mg, 1, 2, :testedgeprop, "5 meters")
173+
@test get_prop(mg, 1, 2, :testedgeprop, "0 meters") == "5 meters"
174+
@test get_prop(mg, 1, 2, :testedgeprop_nonexist, "0 meters") == "0 meters"
175+
@test get_prop(mg, 2, 4, :testedgeprop_nonexist, "0 meters") == "0 meters"
176+
@test get_prop(mg, 2, 1, :testedgeprop, "0 meters") == "0 meters"
177+
@test get_prop(mg, 2, 1, :testedgeprop_nonexist, "0 meters") == "0 meters"
178+
179+
@test get_prop(mg, Edge(1, 2), :testedgeprop, "0 meters") == "5 meters"
180+
@test get_prop(mg, Edge(1, 2), :testedgeprop_nonexist, "0 meters") == "0 meters"
181+
@test get_prop(mg, Edge(2, 4), :testedgeprop_nonexist, "0 meters") == "0 meters"
182+
@test get_prop(mg, Edge(2, 1), :testedgeprop, "0 meters") == "0 meters"
183+
@test get_prop(mg, Edge(2, 1), :testedgeprop_nonexist, "0 meters") == "0 meters"
184+
185+
# graph
186+
set_prop!(mg, :testgraphpprop, "linegraph")
187+
@test get_prop(mg, :testgraphpprop, "circlegraph") == "linegraph"
188+
@test get_prop(mg, :testgraphpprop_nonexist, "circlegraph") == "circlegraph"
138189
end
139190

140191
for gbig in [SimpleGraph(0xff), SimpleDiGraph(0xff)]
@@ -299,7 +350,7 @@ import Base64:
299350
@test weightfield!(mg, :weight) == :weight
300351
@test enumerate_paths(dijkstra_shortest_paths(mg, 1), 3) == [1, 2, 3]
301352

302-
@test set_props!(mg, 1, 2, Dict(:color => :blue, :action => "knows"))
353+
@test set_props!(mg, 1, 2, Dict(:color => :blue, :action => "knows"))
303354
@test length(props(mg, 1, 2)) == 3
304355
@test rem_edge!(mg, 1, 2)
305356
@test length(props(mg, 1, 2)) == 0
@@ -352,12 +403,12 @@ import Base64:
352403
for v in vertices(mga)
353404
set_prop!(mga, v, :name, string(v))
354405
end
355-
set_indexing_prop!(mga,:name)
406+
set_indexing_prop!(mga, :name)
356407
@test get_prop(mga, 1, :name) == "1"
357408
@test get_prop(mga, 5, :name) == "5"
358409
@test rem_vertex!(mga, 1)
359410
@test get_prop(mga, 1, :name) == "5"
360-
@test mga["5",:name] == 1
411+
@test mga["5", :name] == 1
361412
@test isempty(props(mga, 5))
362413

363414
# test for #22
@@ -373,19 +424,19 @@ import Base64:
373424

374425
# test for #72 - Multiple indicies that are not all used
375426
let
376-
test_graph = x-> begin
377-
g=MetaGraph()
378-
set_indexing_prop!(g,:IndexA)
379-
set_indexing_prop!(g,:IndexB)
380-
add_vertex!(g,:IndexA,"A")
381-
x && add_vertex!(g,:IndexA,"B")
382-
x && set_indexing_prop!(g,nv(g),:IndexB,"B")
383-
add_vertex!(g,:IndexB,"C")
427+
test_graph = x -> begin
428+
g = MetaGraph()
429+
set_indexing_prop!(g, :IndexA)
430+
set_indexing_prop!(g, :IndexB)
431+
add_vertex!(g, :IndexA, "A")
432+
x && add_vertex!(g, :IndexA, "B")
433+
x && set_indexing_prop!(g, nv(g), :IndexB, "B")
434+
add_vertex!(g, :IndexB, "C")
384435
g
385436
end
386-
mga=test_graph(true)
387-
rem_vertex!(mga,2)
388-
@test mga==test_graph(false)
437+
mga = test_graph(true)
438+
rem_vertex!(mga, 2)
439+
@test mga == test_graph(false)
389440
end
390441

391442
mga = MetaDiGraph(path_digraph(4))
@@ -482,7 +533,7 @@ end
482533
@test MetaGraphs.index_available(dG, 7, :name, "dgnode_8-anothername") == true
483534

484535
@test_throws ErrorException set_props!(G, 11, Dict(:name => "gnode_3", :other_name => "something11"))
485-
@test_throws ErrorException set_props!(dG,11, Dict(:name => "dgnode_3", :other_name => "something11"))
536+
@test_throws ErrorException set_props!(dG, 11, Dict(:name => "dgnode_3", :other_name => "something11"))
486537
@test_throws KeyError get_prop(G, 11, :other_name)
487538
@test_throws KeyError get_prop(dG, 11, :other_name)
488539

0 commit comments

Comments
 (0)