Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/src/Combinatorics/graphs.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ vertex_edge_graph(p::Polyhedron; modulo_lineality=false)
graph_from_adjacency_matrix
graph_from_edges
graph_from_labeled_edges
induced_subgraph
```

### Modifying graphs
Expand Down
95 changes: 75 additions & 20 deletions src/Combinatorics/Graphs/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1513,7 +1513,8 @@ function visualize(G::Graph{T};
kwargs...) where {T <: Union{Directed, Undirected}}
BG = Polymake.graph.Graph{T}(ADJACENCY=pm_object(G))

defaults = (;VertexLabels = collect(1:n_vertices(G)))
allvert = 1:n_vertices(G)
defaults = (; VertexLabels = has_attribute(G,:vertexlabels) ? getindex.(Ref(G.vertexlabels), allvert) : collect(allvert))
if has_attribute(G, :color)
defaults = merge(defaults,
NamedTuple(k => v for (k, v) in
Expand Down Expand Up @@ -1575,9 +1576,29 @@ _to_string(::Type{Mixed}) = "Mixed"

function Base.show(io::IO, m::MIME"text/plain", G::AbstractGraph{T}) where {T <: GraphTypes}
if n_edges(G) > 0
print(io, "$(_to_string(T)) graph with $(n_vertices(G)) nodes and the following")
labels = labelings(G)
printedges = all(l->!_has_edge_map(getproperty(G,l)), labels)
if printedges
if T == Mixed
println(io, "\nDirected edges:")
for e in edges(G, Directed)
print(io, "($(src(e)), $(dst(e)))")
end
println(io, "\nUndirected edges:")
for e in edges(G, Undirected)
print(io, "($(src(e)), $(dst(e)))")
end
else
println(io, " edges:") # at least one new line is needed
for e in edges(G)
print(io, "($(src(e)), $(dst(e)))")
end
end
end
if !isempty(labels)
print(io, "$(_to_string(T)) graph with $(n_vertices(G)) nodes and the following labeling(s):")
printedges && print(io, "\nand the following")
print(io, " labeling(s):")
for label in labels
println(io, "")
print(io, "label: $label")
Expand All @@ -1594,24 +1615,6 @@ function Base.show(io::IO, m::MIME"text/plain", G::AbstractGraph{T}) where {T <:
end
end
end
else
if T == Mixed
println(io, "$(_to_string(T)) graph with $(n_vertices(G)) nodes and the following") # at least one new line is needed
println(io, "Directed edges:")
for e in edges(G, Directed)
print(io, "($(src(e)), $(dst(e)))")
end
println(io, "")
println(io, "Undirected edges:")
for e in edges(G, Undirected)
print(io, "($(src(e)), $(dst(e)))")
end
else
println(io, "$(_to_string(T)) graph with $(n_vertices(G)) nodes and the following edges:") # at least one new line is needed
for e in edges(G)
print(io, "($(src(e)), $(dst(e)))")
end
end
end
else
print(io, "$(_to_string(T)) graph with $(n_vertices(G)) nodes and no edges")
Expand Down Expand Up @@ -2030,3 +2033,55 @@ function is_acylic(G::Graph{Directed})
end
return !any(a) # The graph is acyclic if all edges have been removed
end

@doc raw"""
induced_subgraph(g::Graph{T}, v::AbstractVector{<:IntegerUnion}; copy_labelings::Bool=true) where {T <: Union{Directed, Undirected}}

Create a new graph induced by `g` on the given subset of vertices.
Please note that the subset of vertices will be sorted ascending before being used.
The original vertices can be identified with the `vertexlabels` labeling.

Unless the keyword argument `copy_labelings` is set to false, all labelings will be transformed and copied to the subgraph.

# Examples
```jldoctest
julia> g = graph_from_edges([[1, 2], [2, 3], [1, 3], [2, 4], [3, 4]])
Undirected graph with 4 nodes and the following edges:
(2, 1)(3, 1)(3, 2)(4, 2)(4, 3)

julia> induced_subgraph(g, 2:4)
Undirected graph with 3 nodes and the following edges:
(2, 1)(3, 1)(3, 2)
and the following labeling(s):
label: vertexlabels
1 -> 2
2 -> 3
3 -> 4
```
"""
function induced_subgraph(g::Graph{T}, v::AbstractVector{<:IntegerUnion}; copy_labelings::Bool=true) where {T <: Union{Directed, Undirected}}
overt = unique(sort(Int.(v)))
pvert = Polymake.Set(Polymake.to_zero_based_indexing(overt))
subg = Polymake.common.induced_subgraph(pm_object(g), pvert)
newsym = T === Directed ? Symbol("GraphAdjacency__Directed::new") : Symbol("GraphAdjacency__Undirected::new")
nsg = Polymake.call_function(:common, newsym, nothing, subg)
Polymake._squeeze(nsg)
og = Graph{T}(nsg)
if !has_attribute(g, :vertexlabels)
# we always do the vertexlabels to keep a reference to the original vertices
label!(og, nothing, Dict(pairs(overt)); name=:vertexlabels)
end
if copy_labelings
for (l, gm) in _graph_maps(g)
el = vl = nothing
if _has_vertex_map(gm)
vl = Dict(pairs(getindex.(Ref(gm), overt)))
end
if _has_edge_map(gm)
el = Dict((src(e),dst(e)) => gm[overt[src(e)],overt[dst(e)]] for e in edges(og))
end
label!(og, el, vl; name=l)
end
end
return og
end
1 change: 1 addition & 0 deletions src/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,7 @@ export induced_automorphism
export induced_cyclic
export induced_map_on_exterior_power
export induced_ring_ordering
export induced_subgraph
export initial
export inneighbors
export inner_automorphism
Expand Down
26 changes: 26 additions & 0 deletions test/Combinatorics/Graph.jl
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,30 @@
rem_edge!(G, 3, 1)
@test is_acylic(G)
end

@testset "subgraph" begin
G = graph_from_edges(Directed, [[1, 2], [2, 3], [3, 1]])
sg = induced_subgraph(G, [1, 2])
@test ne(sg) == 1
@test nv(sg) == 2
@test sg isa Graph{Directed}
G2 = complete_bipartite_graph(3, 3)
sg2 = induced_subgraph(G2, [1, 2, 3])
@test ne(sg2) == 0
@test nv(sg2) == 3

G3 = graph_from_labeled_edges(Undirected, Dict((1, 2) => 4, (2, 3) => 5, (1, 3) => 6), Dict(3 => 9); name=:color)
sg3 = induced_subgraph(G3, [3, 2])
@test ne(sg3) == 1
@test nv(sg3) == 2
@test sg3.color[2] == 9
@test sg3.vertexlabels[2] == 3
@test sg3.color[1,2] == G3.color[2,3] == 5

G4 = complete_graph(4)
label!(G4,nothing,Dict(1=>"first",2=>"second",3=>"third",4=>"fourth"), name=:vertexlabels)
sg4 = induced_subgraph(G4, [2,4])
@test sg4.vertexlabels[1] == "second"
@test sg4.vertexlabels[2] == "fourth"
end
end
Loading