Skip to content
This repository has been archived by the owner on Oct 8, 2021. It is now read-only.

updates in graph_traversal #332

Merged
merged 17 commits into from
Apr 24, 2016
Merged
Show file tree
Hide file tree
Changes from 16 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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ save("mygraph.jgz", g, "mygraph", compress=true)

- **distance:** eccentricity, diameter, periphery, radius, center

- **connectivity:** strongly- and weakly-connected components, bipartite checks, condensation, attracting components
- **connectivity:** strongly- and weakly-connected components, bipartite checks, condensation, attracting components, neighborhood

- **operators:** complement, reverse, reverse!, union, join, intersect, difference,
symmetric difference, blkdiag, induced subgraphs, products (cartesian/scalar)
Expand Down
14 changes: 14 additions & 0 deletions doc/basicmeasures.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,17 @@ common_neighbors(g::Union{LightGraphs.DiGraph,LightGraphs.Graph}, u::Int64, v::I
```
Returns the neighbors common to vertices `u` and `v` in `g`.

### neighborhood
```julia
neighborhood(g, v::Int, d::Int; dir=:out)
```

Returns a vector of the vertices in `g` at distance less or equal to `d` from `v`. If `g` is a `DiGraph` the `dir` optional argument specifies the edge direction the edge direction with respect to `v` (i.e. `:in` or `:out`) to be considered.

### egonet
```julia
egonet(g, v::Int, d::Int; dir=:out)
```

Returns the subgraph of `g` induced by the neighbors of `v` up to distance `d`. If `g` is a `DiGraph` the `dir` optional argument specifies the edge direction the edge direction with respect to `v` (i.e. `:in` or `:out`) to be considered. This is equivalent to `induced_subgraph(g, neighborhood(g, v, d, dir=dir)).`

7 changes: 5 additions & 2 deletions doc/build.jl
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ types:

## Neighbors and Degree

{{degree, indegree, outdegree, Δ, δ, Δout, δout, δin, Δin, degree_histogram, density, neighbors, in_neighbors, all_neighbors, common_neighbors}}
{{degree, indegree, outdegree, Δ, δ, Δout, δout, δin, Δin, degree_histogram, density, neighbors,
in_neighbors, all_neighbors, common_neighbors, neighborhood, egonet}}
"""

@file "centrality.md" """
Expand Down Expand Up @@ -354,7 +355,9 @@ Any graph traversal will traverse an edge only if it is present in the graph. W
## Connectivity / Bipartiteness
`Graph connectivity` functions are defined on both undirected and directed graphs:

{{is_connected, is_strongly_connected, is_weakly_connected, connected_components, strongly_connected_components, weakly_connected_components, has_self_loop, attracting_components, is_bipartite, condensation, period}}
{{is_connected, is_strongly_connected, is_weakly_connected, connected_components,
strongly_connected_components, weakly_connected_components, has_self_loop,
attracting_components, is_bipartite, condensation, period, neighborhood}}

## Cycle Detection
In graph theory, a cycle is defined to be a path that starts from some vertex
Expand Down
2 changes: 1 addition & 1 deletion doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ save("mygraph.jgz", g, "mygraph", compress=true)

- **distance:** eccentricity, diameter, periphery, radius, center

- **connectivity:** strongly- and weakly-connected components, bipartite checks, condensation, attracting components
- **connectivity:** strongly- and weakly-connected components, bipartite checks, condensation, attracting components, neighborhood

- **operators:** complement, reverse, reverse!, union, join, intersect, difference,
symmetric difference, blkdiag, induced subgraphs, products (cartesian/scalar)
Expand Down
38 changes: 25 additions & 13 deletions doc/pathing.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ This function is a high level wrapper around bfs_tree!, use that function for mo

### dfs_tree
```julia
dfs_tree(g::Union{LightGraphs.DiGraph,LightGraphs.Graph}, s::Int64)
dfs_tree(g, s::Int)
```

Provides a depth-first traversal of the graph `g` starting with source vertex `s`, and returns a directed acyclic graph of vertices in the order they were discovered.

### maximum_adjacency_visit
Expand Down Expand Up @@ -62,9 +63,9 @@ Performs a [self-avoiding walk](https://en.wikipedia.org/wiki/Self-avoiding_walk
`Graph connectivity` functions are defined on both undirected and directed graphs:
### is_connected
```julia
is_connected(g::LightGraphs.Graph)
is_connected(g::LightGraphs.DiGraph)
is_connected(g)
```

Returns `true` if `g` is connected. For DiGraphs, this is equivalent to a test of weak connectivity.

### is_strongly_connected
Expand All @@ -83,7 +84,8 @@ Returns `true` if the undirected graph of `g` is connected.
```julia
connected_components(g)
```
Returns the [connected components](https://en.wikipedia.org/wiki/Connectivity_(graph_theory)) of an undirected graph `g` as a vector of components, each represented by a vector of vectors of vertices belonging to the component.

Returns the [connected components](https://en.wikipedia.org/wiki/Connectivity_(graph_theory)) of `g` as a vector of components, each represented by a vector of vertices belonging to the component.

### strongly_connected_components
```julia
Expand Down Expand Up @@ -111,10 +113,11 @@ Returns a vector of vectors of integers representing lists of attracting compone

### is_bipartite
```julia
is_bipartite(g::Union{LightGraphs.DiGraph,LightGraphs.Graph})
is_bipartite(g::Union{LightGraphs.DiGraph,LightGraphs.Graph}, s::Int64)
is_bipartite(g)
is_bipartite(g, v)
```
Will return `true` if graph `g` is [bipartite](https://en.wikipedia.org/wiki/Bipartite_graph).

Will return `true` if graph `g` is [bipartite](https://en.wikipedia.org/wiki/Bipartite_graph). If a node `v` is specified, only the connected component to which it belongs is considered.

### condensation
```julia
Expand All @@ -131,13 +134,21 @@ period(g::LightGraphs.DiGraph)
```
Computes the (common) period for all nodes in a strongly connected graph.

### neighborhood
```julia
neighborhood(g, v::Int, d::Int; dir=:out)
```

Returns a vector of the vertices in `g` at distance less or equal to `d` from `v`. If `g` is a `DiGraph` the `dir` optional argument specifies the edge direction the edge direction with respect to `v` (i.e. `:in` or `:out`) to be considered.

## Cycle Detection
In graph theory, a cycle is defined to be a path that starts from some vertex
`v` and ends up at `v`.
### is_cyclic
```julia
is_cyclic(graph::Union{LightGraphs.DiGraph,LightGraphs.Graph})
is_cyclic(g)
```

Tests whether a graph contains a cycle through depth-first search. It returns `true` when it finds a cycle, otherwise `false`.

## Shortest-Path Algorithms
Expand Down Expand Up @@ -184,16 +195,17 @@ Note that this algorithm may return a large amount of data (it will allocate on
## Path discovery / enumeration
### gdistances
```julia
gdistances(graph::Union{LightGraphs.DiGraph,LightGraphs.Graph}, sources)
gdistances(g, source) -> dists
```
Returns the geodesic distances of graph `g` from source vertex `s` or a set of source vertices `ss`.

Returns a vector filled with the geodesic distances of vertices in `g` from vertex/vertices `source`. For vertices in disconnected components the default distance is -1.

### gdistances!
```julia
gdistances!{DMap}(graph::Union{LightGraphs.DiGraph,LightGraphs.Graph}, s::Int64, dists::DMap)
gdistances!{DMap}(graph::Union{LightGraphs.DiGraph,LightGraphs.Graph}, sources::AbstractArray{Int64,1}, dists::DMap)
gdistances!(g, source, dists) -> dists
```
Returns the geodesic distances of graph `g` from source vertex `s` or a set of source vertices `ss`.

Fills `dists` with the geodesic distances of vertices in `g` from vertex/vertices `source`. `dists` can be either a vector or a dictionary.

### enumerate_paths
```julia
Expand Down
10 changes: 5 additions & 5 deletions src/LightGraphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ catch
end

import Base: write, ==, <, *, isless, issubset, complement, union, intersect,
reverse, reverse!, blkdiag, getindex, show, print, copy, in,
reverse, reverse!, blkdiag, getindex, setindex!, show, print, copy, in,
sum, size, sparse, eltype, length, ndims, issym, transpose,
ctranspose, join, start, next, done, eltype
ctranspose, join, start, next, done, eltype, get


# core
Expand All @@ -48,7 +48,7 @@ crosspath,
# graph visit
SimpleGraphVisitor, TrivialGraphVisitor, LogGraphVisitor,
discover_vertex!, open_vertex!, close_vertex!,
examine_neighbor!, visited_vertices, traverse_graph, traverse_graph_withlog,
examine_neighbor!, visited_vertices, traverse_graph!, traverse_graph_withlog,

# bfs
BreadthFirst, gdistances, gdistances!, bfs_tree, is_bipartite, bipartite_map,
Expand All @@ -62,7 +62,7 @@ randomwalk, saw, non_backtracking_randomwalk,
# connectivity
connected_components, strongly_connected_components, weakly_connected_components,
is_connected, is_strongly_connected, is_weakly_connected, period,
condensation, attracting_components,
condensation, attracting_components, neighborhood, egonet,

# cliques
maximal_cliques,
Expand Down Expand Up @@ -100,7 +100,7 @@ maximum_weight_maximal_matching, MatchingResult,
# randgraphs
erdos_renyi, watts_strogatz, random_regular_graph, random_regular_digraph, random_configuration_model,
StochasticBlockModel, make_edgestream, nearbipartiteSBM, blockcounts, blockfractions,
stochastic_block_model,
stochastic_block_model,

#community
modularity, community_detection_nback, core_periphery_deg,
Expand Down
93 changes: 73 additions & 20 deletions src/connectivity.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
# licensing details.


"""connected_components! produces a label array of components
"""
connected_components!(label::Vector{Int}, g::SimpleGraph)

Fills `label` with the `id` of the connected component to which it belongs.

Arguments:
label: a place to store the output
Expand All @@ -21,14 +24,14 @@ function connected_components!(label::Vector{Int}, g::SimpleGraph)
# passed to components(a)
nvg = nv(g)
visitor = LightGraphs.ComponentVisitorVector(label, 0)
colormap = zeros(Int,nvg)
que = Vector{Int}()
sizehint!(que, nvg)
colormap = fill(-1,nvg)
queue = Vector{Int}()
sizehint!(queue, nvg)
for v in 1:nvg
if label[v] == 0
visitor.labels[v] = v
visitor.seed = v
traverse_graph(g, BreadthFirst(), v, visitor; colormap=colormap, que=que)
traverse_graph!(g, BreadthFirst(), v, visitor; vertexcolormap=colormap, queue=queue)
end
end
return label
Expand All @@ -51,25 +54,25 @@ function components_dict(labels::Vector{Int})
return d
end

"""components(labels) converts an array of labels to a Vector{Vector{Int}} of components
"""
components(labels::Vector{Int})

Converts an array of labels to a Vector{Vector{Int}} of components

Arguments:
c = labels[i] => vertex i belongs to component c.
Output:
vs = c[i] => vertices in vs belong to component i.
a = d[i] => if label[v[j]]==i then j in c[a] end
a = d[i] => if labels[v]==i then v in c[a] end
"""
function components(labels::Vector{Int})
d = Dict{Int, Int}()
c = Vector{Vector{Int}}()
i = 1
for (v,l) in enumerate(labels)
index = get(d, l, i)
d[l] = index
index = get!(d, l, i)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is nice.

if length(c) >= index
vec = c[index]
push!(vec, v)
c[index] = vec
push!(c[index], v)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. I don't know why we did it the old way.

else
push!(c, [v])
i += 1
Expand All @@ -78,19 +81,26 @@ function components(labels::Vector{Int})
return c, d
end

"""Returns the [connected components](https://en.wikipedia.org/wiki/Connectivity_(graph_theory))
of an undirected graph `g` as a vector of components, each represented by a
vector of vectors of vertices belonging to the component.
"""
function connected_components(g)
connected_components(g)

Returns the [connected components](https://en.wikipedia.org/wiki/Connectivity_(graph_theory))
of `g` as a vector of components, each represented by a
vector of vertices belonging to the component.
"""
function connected_components(g::SimpleGraph)
label = zeros(Int, nv(g))
connected_components!(label, g)
c, d = components(label)
return c
end

"""Returns `true` if `g` is connected.
For DiGraphs, this is equivalent to a test of weak connectivity."""
"""
is_connected(g)

Returns `true` if `g` is connected.
For DiGraphs, this is equivalent to a test of weak connectivity.
"""
is_connected(g::Graph) = length(connected_components(g)) == 1
is_connected(g::DiGraph) = is_weakly_connected(g)

Expand Down Expand Up @@ -123,7 +133,7 @@ function discover_vertex!(vis::TarjanVisitor, v)
end

function examine_neighbor!(vis::TarjanVisitor, v, w, w_color::Int, e_color::Int)
if w_color > 0 # 1 means added seen, but not explored; 2 means closed
if w_color >= 0 # >=0 means added seen
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch! thanks

while vis.index[w] > 0 && vis.index[w] < vis.lowlink[end]
pop!(vis.lowlink)
end
Expand All @@ -150,7 +160,7 @@ function strongly_connected_components(g::DiGraph)
for v in vertices(g)
if cmap[v] == 0 # 0 means not visited yet
visitor = TarjanVisitor(nvg)
traverse_graph(g, DepthFirst(), v, visitor, vertexcolormap=cmap)
traverse_graph!(g, DepthFirst(), v, visitor, vertexcolormap=cmap)
for component in visitor.components
push!(components, component)
end
Expand Down Expand Up @@ -227,3 +237,46 @@ function attracting_components(g::DiGraph)
end
return scc[attracting]
end

type NeighborhoodVisitor <: SimpleGraphVisitor
d::Int
neigs::Vector{Int}
end

NeighborhoodVisitor(d::Int) = NeighborhoodVisitor(d, Vector{Int}())

function examine_neighbor!(visitor::NeighborhoodVisitor, u::Int, v::Int, ucolor::Int, vcolor::Int, ecolor::Int)
ucolor >= visitor.d && return false
if vcolor < 0
push!(visitor.neigs, v)
end
return true
end


"""
neighborhood(g, v::Int, d::Int; dir=:out)

Returns a vector of the vertices in `g` at distance less or equal to `d`
from `v`. If `g` is a `DiGraph` the `dir` optional argument specifies the edge direction
the edge direction with respect to `v` (i.e. `:in` or `:out`) to be considered.
"""
function neighborhood(g::SimpleGraph, v::Int, d::Int; dir=:out)
@assert d >= 0 "Distance has to be greater then zero."
visitor = NeighborhoodVisitor(d)
push!(visitor.neigs, v)
traverse_graph!(g, BreadthFirst(), v, visitor,
vertexcolormap=Dict{Int,Int}(), dir=dir)
return visitor.neigs
end


"""
egonet(g, v::Int, d::Int; dir=:out)

Returns the subgraph of `g` induced by the neighbors of `v` up to distance
`d`. If `g` is a `DiGraph` the `dir` optional argument specifies
the edge direction the edge direction with respect to `v` (i.e. `:in` or `:out`)
to be considered. This is equivalent to `induced_subgraph(g, neighborhood(g, v, d, dir=dir)).`
"""
egonet(g::SimpleGraph, v::Int, d::Int; dir=:out) = induced_subgraph(g, neighborhood(g, v, d, dir=dir))
Loading