|
| 1 | +""" |
| 2 | + ReverseView{T<:Integer,G<:AbstractGraph} <: AbstractGraph{T} |
| 3 | +
|
| 4 | +A graph view that wraps a directed graph and reverse the direction of every edge. |
| 5 | +
|
| 6 | +!!! warning |
| 7 | + Some properties of the view (e.g. the number of edges) are forwarded from the |
| 8 | + underlying graph and are not recomputed. Modifying the underlying graph after |
| 9 | + constructing the view may lead to incorrect results. |
| 10 | +
|
| 11 | +# Examples |
| 12 | +```jldoctest |
| 13 | +julia> using Graphs |
| 14 | +
|
| 15 | +julia> g = SimpleDiGraph(2); |
| 16 | +
|
| 17 | +julia> add_edge!(g, 1, 2); |
| 18 | +
|
| 19 | +julia> rg = ReverseView(g); |
| 20 | +
|
| 21 | +julia> neighbors(rg, 1) |
| 22 | +Int64[] |
| 23 | +
|
| 24 | +julia> neighbors(rg, 2) |
| 25 | +1-element Vector{Int64}: |
| 26 | + 1 |
| 27 | +``` |
| 28 | +""" |
| 29 | +struct ReverseView{T<:Integer,G<:AbstractGraph} <: AbstractGraph{T} |
| 30 | + g::G |
| 31 | + |
| 32 | + @traitfn ReverseView{T,G}(g::::(IsDirected)) where {T<:Integer,G<:AbstractGraph{T}} = new( |
| 33 | + g |
| 34 | + ) |
| 35 | + @traitfn ReverseView{T,G}(g::::(!IsDirected)) where {T<:Integer,G<:AbstractGraph{T}} = throw( |
| 36 | + ArgumentError("Your graph needs to be directed") |
| 37 | + ) |
| 38 | +end |
| 39 | + |
| 40 | +ReverseView(g::G) where {T<:Integer,G<:AbstractGraph{T}} = ReverseView{T,G}(g) |
| 41 | + |
| 42 | +wrapped_graph(g::ReverseView) = g.g |
| 43 | + |
| 44 | +Graphs.is_directed(::ReverseView{T,G}) where {T,G} = true |
| 45 | +Graphs.is_directed(::Type{<:ReverseView{T,G}}) where {T,G} = true |
| 46 | + |
| 47 | +Graphs.edgetype(g::ReverseView) = Graphs.edgetype(g.g) |
| 48 | +Graphs.has_vertex(g::ReverseView, v) = Graphs.has_vertex(g.g, v) |
| 49 | +Graphs.ne(g::ReverseView) = Graphs.ne(g.g) |
| 50 | +Graphs.nv(g::ReverseView) = Graphs.nv(g.g) |
| 51 | +Graphs.vertices(g::ReverseView) = Graphs.vertices(g.g) |
| 52 | +Graphs.edges(g::ReverseView) = (reverse(e) for e in Graphs.edges(g.g)) |
| 53 | +Graphs.has_edge(g::ReverseView, s, d) = Graphs.has_edge(g.g, d, s) |
| 54 | +Graphs.inneighbors(g::ReverseView, v) = Graphs.outneighbors(g.g, v) |
| 55 | +Graphs.outneighbors(g::ReverseView, v) = Graphs.inneighbors(g.g, v) |
| 56 | + |
| 57 | +""" |
| 58 | + UndirectedView{T<:Integer,G<:AbstractGraph} <: AbstractGraph{T} |
| 59 | +
|
| 60 | +A graph view that wraps a directed graph and consider every edge as undirected. |
| 61 | +
|
| 62 | +!!! warning |
| 63 | + Some properties of the view, such as the number of edges, are cached at |
| 64 | + construction time. Modifying the underlying graph after constructing the view |
| 65 | + will lead to incorrect results. |
| 66 | +
|
| 67 | +# Examples |
| 68 | +```jldoctest |
| 69 | +julia> using Graphs |
| 70 | +
|
| 71 | +julia> g = SimpleDiGraph(2); |
| 72 | +
|
| 73 | +julia> add_edge!(g, 1, 2); |
| 74 | +
|
| 75 | +julia> ug = UndirectedView(g); |
| 76 | +
|
| 77 | +julia> neighbors(ug, 1) |
| 78 | +1-element Vector{Int64}: |
| 79 | + 2 |
| 80 | +
|
| 81 | +julia> neighbors(ug, 2) |
| 82 | +1-element Vector{Int64}: |
| 83 | + 1 |
| 84 | +``` |
| 85 | +""" |
| 86 | +struct UndirectedView{T<:Integer,G<:AbstractGraph} <: AbstractGraph{T} |
| 87 | + g::G |
| 88 | + ne::Int |
| 89 | + @traitfn function UndirectedView{T,G}( |
| 90 | + g::::(IsDirected) |
| 91 | + ) where {T<:Integer,G<:AbstractGraph{T}} |
| 92 | + ne = count(e -> src(e) <= dst(e) || !has_edge(g, dst(e), src(e)), Graphs.edges(g)) |
| 93 | + return new(g, ne) |
| 94 | + end |
| 95 | + |
| 96 | + @traitfn UndirectedView{T,G}(g::::(!IsDirected)) where {T<:Integer,G<:AbstractGraph{T}} = throw( |
| 97 | + ArgumentError("Your graph needs to be directed") |
| 98 | + ) |
| 99 | +end |
| 100 | + |
| 101 | +UndirectedView(g::G) where {T<:Integer,G<:AbstractGraph{T}} = UndirectedView{T,G}(g) |
| 102 | + |
| 103 | +""" |
| 104 | + wrapped_graph(g) |
| 105 | +
|
| 106 | +Return the graph wrapped by `g` |
| 107 | +""" |
| 108 | +function wrapped_graph end |
| 109 | + |
| 110 | +wrapped_graph(g::UndirectedView) = g.g |
| 111 | + |
| 112 | +Graphs.is_directed(::UndirectedView) = false |
| 113 | +Graphs.is_directed(::Type{<:UndirectedView}) = false |
| 114 | + |
| 115 | +Graphs.edgetype(g::UndirectedView) = Graphs.edgetype(g.g) |
| 116 | +Graphs.has_vertex(g::UndirectedView, v) = Graphs.has_vertex(g.g, v) |
| 117 | +Graphs.ne(g::UndirectedView) = g.ne |
| 118 | +Graphs.nv(g::UndirectedView) = Graphs.nv(g.g) |
| 119 | +Graphs.vertices(g::UndirectedView) = Graphs.vertices(g.g) |
| 120 | +function Graphs.has_edge(g::UndirectedView, s, d) |
| 121 | + return Graphs.has_edge(g.g, s, d) || Graphs.has_edge(g.g, d, s) |
| 122 | +end |
| 123 | +Graphs.inneighbors(g::UndirectedView, v) = Graphs.all_neighbors(g.g, v) |
| 124 | +Graphs.outneighbors(g::UndirectedView, v) = Graphs.all_neighbors(g.g, v) |
| 125 | +function Graphs.edges(g::UndirectedView) |
| 126 | + return ( |
| 127 | + begin |
| 128 | + (u, v) = src(e), dst(e) |
| 129 | + if (v < u) |
| 130 | + (u, v) = (v, u) |
| 131 | + end |
| 132 | + Edge(u, v) |
| 133 | + end for |
| 134 | + e in Graphs.edges(g.g) if (src(e) <= dst(e) || !has_edge(g.g, dst(e), src(e))) |
| 135 | + ) |
| 136 | +end |
0 commit comments