From 7c4e1680ef0c6d7e19eb37feebf4deefd3d54aca Mon Sep 17 00:00:00 2001 From: Simon Schoelly Date: Sun, 18 Apr 2021 12:09:41 +0200 Subject: [PATCH 1/6] Replace nothing with () in edges function --- src/abstractvaluegraph.jl | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/abstractvaluegraph.jl b/src/abstractvaluegraph.jl index d108443..9ad76c7 100644 --- a/src/abstractvaluegraph.jl +++ b/src/abstractvaluegraph.jl @@ -222,12 +222,12 @@ LG.vertices(g::AbstractValGraph) = OneTo{eltype(g)}(nv(g)) LG.has_vertex(g::AbstractValGraph, v) = v ∈ vertices(g) """ - edges(g::AbstractValGraph[, key]) + edges(g::AbstractValGraph, key=()) Return the edges of `g`. By default add no edge values but when `key=:` then add edge values. """ -LG.edges(g::AbstractValGraph, key=nothing) = ValEdgeIter(g, key) +LG.edges(g::AbstractValGraph, key=()) = ValEdgeIter(g, key) LG.edgetype(g::AbstractValGraph) = eltype(edges(g)) @@ -646,7 +646,7 @@ inedgevals(g::AbstractValGraph, v, ::Colon) = struct ValEdgeIter{G<:AbstractValGraph, key} <: AbstractEdgeIter graph::G - function ValEdgeIter{G}(g::G, key::Union{Colon, Nothing}) where {G} + function ValEdgeIter{G}(g::G, key::Union{Colon, Tuple{}}) where {G} return new{G, key}(g) end @@ -662,7 +662,7 @@ function Base.eltype(::Type{<:ValEdgeIter{G, key}}) where {G, key} V = eltype(G) E_VALS = edgevals_type(G) - if key == nothing + if key == () # TODO it might better to return an empty named tuple type in case # E_VALS is a named tuple, but then we need to adjust the iterators return E{V, Tuple{}} @@ -713,11 +713,7 @@ function Base.iterate(iter::ValEdgeIter{G, key}, state) where {G, key} end v, outneighbors_state = outneighbors_next - edge = if key == nothing - eltype(iter)(u, v, ()) - else - eltype(iter)(u, v, get_edgeval(g, u, v, :)) - end + edge = eltype(iter)(u, v, get_edgeval(g, u, v, key)) outneighbors_next = iterate(outneighbors_iter, outneighbors_state) From d9f212b94f5077b8f53d07edb32eefea3dda21f3 Mon Sep 17 00:00:00 2001 From: Simon Schoelly Date: Sun, 18 Apr 2021 12:21:16 +0200 Subject: [PATCH 2/6] Replace nothing with () in edges function --- src/graphwrappers.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphwrappers.jl b/src/graphwrappers.jl index 4cc209a..cbf54ec 100644 --- a/src/graphwrappers.jl +++ b/src/graphwrappers.jl @@ -237,6 +237,6 @@ end function _generate_wrapped_function!(::Val{:edges}, GT) - return :(SimpleValueGraphs.edges(g::$GT, key=nothing) = edges(wrapped_graph(g), key)) + return :(SimpleValueGraphs.edges(g::$GT, key=()) = edges(wrapped_graph(g), key)) end From e6d8c6799c113b7e4090f3d91a954e660e2c7773 Mon Sep 17 00:00:00 2001 From: Simon Schoelly Date: Sun, 18 Apr 2021 14:34:38 +0200 Subject: [PATCH 3/6] Allow more key variants for get_edgeval --- src/abstractvaluegraph.jl | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/abstractvaluegraph.jl b/src/abstractvaluegraph.jl index 9ad76c7..3b81e74 100644 --- a/src/abstractvaluegraph.jl +++ b/src/abstractvaluegraph.jl @@ -408,6 +408,21 @@ function get_edgeval(g::AbstractValGraph, s, d, ::Colon) return E_VALS(get_edgeval(g, s, d, i) for i in OneTo(length(E_VALS.types))) end + +function get_edgeval(g::AbstractValGraph, s, d, keys::Union{NTuple{N, Int} where N, NTuple{N, Symbol} where N}) + + # TODO should be cleaned up, maybe also a bit more optimized with regards to constant propagation + E_VALS = edgevals_type(g) + E_VALS_RESULT = if E_VALS <: Tuple + Tuple{map(i -> fieldtype(E_VALS, i), keys)...} + elseif keys isa NTuple{N, Int} where N + NamedTuple{map(i -> Base.fieldname(E_VALS, i), keys), Tuple{map(i -> fieldtype(E_VALS, i), keys)...}} + else + NamedTuple{keys, Tuple{map(i -> fieldtype(E_VALS, i), keys)...}} + end + return E_VALS_RESULT(get_edgeval(g, s, d, key) for key in keys) +end + # ----------------------------------------------------- # get_edgeval_or # ----------------------------------------------------- From 0445a165e8cfa59f884ab3a6ba98017babeb6baf Mon Sep 17 00:00:00 2001 From: Simon Schoelly Date: Sun, 18 Apr 2021 15:03:14 +0200 Subject: [PATCH 4/6] Return correct tuple type from edges --- src/abstractvaluegraph.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/abstractvaluegraph.jl b/src/abstractvaluegraph.jl index 3b81e74..c894f22 100644 --- a/src/abstractvaluegraph.jl +++ b/src/abstractvaluegraph.jl @@ -680,7 +680,7 @@ function Base.eltype(::Type{<:ValEdgeIter{G, key}}) where {G, key} if key == () # TODO it might better to return an empty named tuple type in case # E_VALS is a named tuple, but then we need to adjust the iterators - return E{V, Tuple{}} + return E{V, (E_VALS <: NamedTuple) ? @NamedTuple{} : Tuple{}} end return E{V, E_VALS} From 8c4b1a036a06996425a3f41bca32f335fb3ca1e9 Mon Sep 17 00:00:00 2001 From: Simon Schoelly Date: Tue, 27 Apr 2021 23:10:04 +0200 Subject: [PATCH 5/6] Specify correct key types for edges --- src/abstractvaluegraph.jl | 51 +++++++++++++++++++++++++------------- src/valuegraph.jl | 13 ++++++++-- test/abstractvaluegraph.jl | 2 +- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/abstractvaluegraph.jl b/src/abstractvaluegraph.jl index c894f22..724829f 100644 --- a/src/abstractvaluegraph.jl +++ b/src/abstractvaluegraph.jl @@ -1,4 +1,8 @@ + +# TODO might move that somewhere else +const MultiKeyTypes = Union{Colon, NTuple{N, Int} where N, NTuple{N, Symbol} where N} + # ====================================================== # AbstractValGraph structure # ====================================================== @@ -409,18 +413,37 @@ function get_edgeval(g::AbstractValGraph, s, d, ::Colon) end +function subtuple_type(T::Union{Type{<:Tuple}, Type{<:NamedTuple}}, ::Colon) + + return T +end + +function subtuple_type(T::Type{<:Tuple}, keys::NTuple{N, Int} where N) + + return Tuple{map(i -> fieldtype(T, i), keys)...} +end + +function subtuple_type(T::Type{<:NamedTuple}, keys::NTuple{0}) + + return @NamedTuple{} +end + +function subtuple_type(T::Type{<:NamedTuple}, keys::NTuple{N, Int} where N) + + return NamedTuple{map(i -> Base.fieldname(T, i), keys), Tuple{map(i -> fieldtype(T, i), keys)...}} +end + +function subtuple_type(T::Type{<:NamedTuple}, keys::NTuple{N, Symbol} where N) + + return NamedTuple{keys, Tuple{map(i -> fieldtype(T, i), keys)...}} +end + + function get_edgeval(g::AbstractValGraph, s, d, keys::Union{NTuple{N, Int} where N, NTuple{N, Symbol} where N}) # TODO should be cleaned up, maybe also a bit more optimized with regards to constant propagation - E_VALS = edgevals_type(g) - E_VALS_RESULT = if E_VALS <: Tuple - Tuple{map(i -> fieldtype(E_VALS, i), keys)...} - elseif keys isa NTuple{N, Int} where N - NamedTuple{map(i -> Base.fieldname(E_VALS, i), keys), Tuple{map(i -> fieldtype(E_VALS, i), keys)...}} - else - NamedTuple{keys, Tuple{map(i -> fieldtype(E_VALS, i), keys)...}} - end - return E_VALS_RESULT(get_edgeval(g, s, d, key) for key in keys) + E_VALS = subtuple_type(edgevals_type(g), keys) + return E_VALS(get_edgeval(g, s, d, key) for key in keys) end # ----------------------------------------------------- @@ -661,7 +684,7 @@ inedgevals(g::AbstractValGraph, v, ::Colon) = struct ValEdgeIter{G<:AbstractValGraph, key} <: AbstractEdgeIter graph::G - function ValEdgeIter{G}(g::G, key::Union{Colon, Tuple{}}) where {G} + function ValEdgeIter{G}(g::G, key::MultiKeyTypes) where {G} return new{G, key}(g) end @@ -675,13 +698,7 @@ function Base.eltype(::Type{<:ValEdgeIter{G, key}}) where {G, key} E = is_directed(G) ? ValDiEdge : ValEdge V = eltype(G) - E_VALS = edgevals_type(G) - - if key == () - # TODO it might better to return an empty named tuple type in case - # E_VALS is a named tuple, but then we need to adjust the iterators - return E{V, (E_VALS <: NamedTuple) ? @NamedTuple{} : Tuple{}} - end + E_VALS = subtuple_type(edgevals_type(G), key) return E{V, E_VALS} end diff --git a/src/valuegraph.jl b/src/valuegraph.jl index e87dd46..0a87e6b 100644 --- a/src/valuegraph.jl +++ b/src/valuegraph.jl @@ -1238,7 +1238,8 @@ inedgevals(g::ValDiGraph, v::Integer, key::Integer) = g.redgevals[key][v] # Iterators # ==================================================================== - +# TODO temporarily commented out +#= @inline function Base.iterate(eit::ValEdgeIter{<:ValGraph, key}, state=(one(eltype(eit.graph)), 1)) where {key} g = eit.graph @@ -1255,11 +1256,14 @@ inedgevals(g::ValDiGraph, v::Integer, key::Integer) = g.redgevals[key][v] i = searchsortedfirst(fadjlist[u], u) continue end + e = eltype(eit)(u, v, get_edgeval(g, u, v, key)) + #= e = if key == nothing ValEdge(u, list_u[i], ()) else ValEdge(u, list_u[i], values_for_index(edgevals, edgevals_type(g), u, i)) end + =# state = (u, i + 1) return e, state @@ -1269,7 +1273,8 @@ inedgevals(g::ValDiGraph, v::Integer, key::Integer) = g.redgevals[key][v] @inbounds (n == 0 || i > length(fadjlist[n])) && return nothing - e = ValEdge(n, n, values_for_index(edgevals, edgevals_type(g), u, i)) + # e = ValEdge(n, n, values_for_index(edgevals, edgevals_type(g), u, i)) + e = eltype(eit)(u, v, get_edgeval(g, u, v, key)) state = (u, i + 1) return e, state end @@ -1293,15 +1298,19 @@ function Base.iterate( i = 1 continue end + #= e = if key == nothing ValDiEdge(u, fadjlist[u][i], ()) else ValDiEdge(u, fadjlist[u][i], values_for_index(edgevals, edgevals_type(g), u, i)) end + =# + e = eltype(iter)(u, v, get_edgeval(g, u, v, key)) return e, (u, i + 1) end return nothing end +=# diff --git a/test/abstractvaluegraph.jl b/test/abstractvaluegraph.jl index d548ae9..7ce3a4a 100644 --- a/test/abstractvaluegraph.jl +++ b/test/abstractvaluegraph.jl @@ -297,7 +297,7 @@ end g2 = DummyValGraph(ValDiGraph{UInt8}(0; edgeval_types=(a=UInt16, b=UInt32))) @test edgetype(g1) == ValEdge{Int8, Tuple{}} - @test edgetype(g2) == ValDiEdge{UInt8, Tuple{}} + @test edgetype(g2) == ValDiEdge{UInt8, @NamedTuple{}} end @testset "ne" begin From ddb986879dda56dac170bf993b40c629a62bdcd9 Mon Sep 17 00:00:00 2001 From: Simon Schoelly Date: Tue, 27 Apr 2021 23:51:14 +0200 Subject: [PATCH 6/6] More key types for more edge function --- src/abstractvaluegraph.jl | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/abstractvaluegraph.jl b/src/abstractvaluegraph.jl index 724829f..8b9978d 100644 --- a/src/abstractvaluegraph.jl +++ b/src/abstractvaluegraph.jl @@ -100,7 +100,10 @@ function edgevals_type(G::Type{<:AbstractValGraph}, key::Symbol) return fieldtype(edgevals_type(G), key) end +function edgevals_type(G::Type{<:AbstractValGraph}, keys::MultiKeyTypes) + return subtuple_type(edgevals_type(G), keys) +end # ------------------------------------------------------ # graphvals_type # ------------------------------------------------------ @@ -226,14 +229,15 @@ LG.vertices(g::AbstractValGraph) = OneTo{eltype(g)}(nv(g)) LG.has_vertex(g::AbstractValGraph, v) = v ∈ vertices(g) """ - edges(g::AbstractValGraph, key=()) + edges(g::AbstractValGraph, keys=()) -Return the edges of `g`. By default add no edge values -but when `key=:` then add edge values. +Return the edges of `g`. +The argument keys specifies which edge values to return. Can be either a tuple +of `Int`'s or `Symbol`'s, or ':' to return all edge values. """ -LG.edges(g::AbstractValGraph, key=()) = ValEdgeIter(g, key) +LG.edges(g::AbstractValGraph, keys=()) = ValEdgeIter(g, keys) -LG.edgetype(g::AbstractValGraph) = eltype(edges(g)) +LG.edgetype(g::AbstractValGraph, keys=()) = eltype(edges(g, keys)) LG.ne(g::AbstractValGraph) = length(edges(g)) @@ -381,11 +385,11 @@ get_edgeval(g::AbstractValGraph, s, d, key::Symbol) = get_edgeval(g::OneEdgeValGraph, s, d) = get_edgeval(g, s, d, 1) """ - get_edgeval(g::AbstractValGraph, s, d, :) + get_edgeval(g::AbstractValGraph, s, d, keys) -Return all values associated with the edge `s -> d` in `g`. +Return multiple values associated with the edge `s -> d` in `g`. -Throw an exception if the graph does not contain such an edge. +Keys can either be a tuple of keys (`Int` or `Symbol`) or `:` to return all keys. ### See also [`get_edgeval_or`](@ref), [`set_edgeval!`](@ref) @@ -639,12 +643,12 @@ outedgevals(g::AbstractValGraph, u, key::Integer) = """ - outedgevals(g::AbstractValGraph, v, :) + outedgevals(g::AbstractValGraph, v, keys) -Return an iterator of all edge values of outgoing edges from `v` to its neighbors. +Return an iterator of all edge values for the specified `keys` of outgoing edges from `v` to its neighbors """ -outedgevals(g::AbstractValGraph, u, ::Colon) = - [get_edgeval(g, u, v, :) for v in outneighbors(g, u)] +outedgevals(g::AbstractValGraph, u, keys::MultiKeyTypes) = + [get_edgeval(g, u, v, keys) for v in outneighbors(g, u)] # ------------------------------------------------------ # inedgevals @@ -669,12 +673,13 @@ inedgevals(g::AbstractValGraph, v, key::Integer) = [get_edgeval(g, u, v, key) for u in inneighbors(g, v)] """ - inedgevals(g::AbstractValGraph, v, :) + inedgevals(g::AbstractValGraph, v, keys) Return an iterator of all edge values of ingoing edges from neighbors of `v`. +Return an iterator of all edge values for the specified `keys` ingoing edges from neighbors of `v`. """ -inedgevals(g::AbstractValGraph, v, ::Colon) = - [get_edgeval(g, u, v, :) for u in inneighbors(g, v)] +inedgevals(g::AbstractValGraph, v, keys::MultiKeyTypes) = + [get_edgeval(g, u, v, keys) for u in inneighbors(g, v)] # ====================================================== # Edge Iterator