Skip to content

Commit 77ed4d4

Browse files
committed
Add Wilson's algorithm for comparison
1 parent 3013e74 commit 77ed4d4

File tree

1 file changed

+80
-6
lines changed

1 file changed

+80
-6
lines changed

src/graph/rooted_spanning_forest.jl

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""
22
RootedSpanningForest{T<:LG.SimpleDiGraph{Int64}} <: AbstractGraphPointProcess{T}
33
4-
Concrete type reprensenting a point process defined on the edges of a `graph` characterizing the uniform distribution on the [spanning forests](https://en.wikipedia.org/wiki/Spanning_tree) of `graph` rooted at `roots`.
4+
Concrete type reprensenting a point process defined on the edges of a **connected** `graph` characterizing the uniform distribution on the directed [spanning forests](https://en.wikipedia.org/wiki/Spanning_tree) of `graph` rooted at `roots`.
55
66
It can be viewed as a the product distribution of the uniform distribution on the set of neighbors of each vertex conditioned on forming no cycles.
77
@@ -12,7 +12,7 @@ The object has two fields:
1212
1313
**See also**
1414
15-
Section 4.2 of [GuJeLi19](@cite).
15+
- Section 4.2 of [GuJeLi19](@cite).
1616
1717
# Example
1818
@@ -64,10 +64,10 @@ function RootedSpanningForest(
6464
if LG.is_connected(graph)
6565
return RootedSpanningForest{LG.SimpleDiGraph{T}}(graph, roots_)
6666
else
67-
throw(DomainError(graph, "graph should be connected"))
67+
throw(DomainError(graph, "The graph must be connected"))
6868
end
6969
else
70-
throw(DomainError(roots, "some roots not contained in vertices(graph)"))
70+
throw(DomainError(roots, "roots must be contained in vertices(graph)"))
7171
end
7272
end
7373

@@ -96,7 +96,10 @@ end
9696
pp::RootedSpanningForest{T}
9797
)::T where {T<:LG.SimpleDiGraph{Int64}}
9898
99-
Generate a rooted spanning forest of `pp.graph`, uniformly at random among all rooted spanning forests rooted at `pp.roots`, using Partial Rejection Sampling (PRS), see Section 4.2 of [GuJeLi19](@cite).
99+
Generate a rooted spanning forest of `pp.`graph` with prescribed `pp.roots`, uniformly at random among all rooted spanning forests rooted at `pp.roots`, using Partial Rejection Sampling (PRS).
100+
101+
**See also**
102+
- Section 4.2 of [GuJeLi19](@cite).
100103
101104
# Example
102105
@@ -123,7 +126,10 @@ end
123126
roots
124127
)::LG.SimpleDiGraph{T} where {T}
125128
126-
Generate a rooted spanning forest from a **connected** `graph`, uniformly at random among all rooted spanning forests rooted at `roots`, using Wilson's algorithm.
129+
Generate a rooted spanning forest from a **connected** `graph` with prescribed `roots`, uniformly at random among all rooted spanning forests rooted at `roots`, using Partial Rejection Sampling.
130+
131+
**See also**
132+
- Section 4.2 of [GuJeLi19](@cite).
127133
"""
128134
function _generate_sample_rooted_spanning_forest_prs(
129135
rng::Random.AbstractRNG,
@@ -146,3 +152,71 @@ function _generate_sample_rooted_spanning_forest_prs(
146152
end
147153
return g
148154
end
155+
156+
function _generate_sample_rooted_spanning_forest_prs(
157+
graph::LG.SimpleGraph{T},
158+
roots
159+
)::LG.SimpleDiGraph{T} where {T}
160+
return _generate_sample_rooted_spanning_forest_prs(Random.default_rng(), graph, roots)
161+
end
162+
163+
@doc raw"""
164+
_generate_sample_rooted_spanning_forest_wilson(
165+
[rng::Random.AbstractRNG,]
166+
graph::LG.SimpleGraph{T},
167+
roots
168+
)
169+
170+
Generate a spanning forest of a **connected** `graph` with prescribed `roots`, uniformly at random among all rooted spanning forests rooted at `roots`, using [Wilson's algorithm](https://en.wikipedia.org/wiki/Loop-erased_random_walk#Uniform_spanning_tree).
171+
172+
**See also**
173+
- [RandomForests.jl implementation](https://gricad-gitlab.univ-grenoble-alpes.fr/barthesi/RandomForests.jl/-/blob/master/src/random_spanning_tree.jl).
174+
"""
175+
function _generate_sample_rooted_spanning_forest_wilson(
176+
rng::Random.AbstractRNG,
177+
graph::LG.SimpleGraph{T},
178+
roots
179+
)::LG.SimpleDiGraph{T} where {T}
180+
in_tree = falses(LG.nv(graph))
181+
for r in roots
182+
@inbounds in_tree[r] = true
183+
end
184+
185+
successors = zeros(T, LG.nv(graph))
186+
for i in LG.vertices(graph)
187+
# Run a natural random walk on g from i until the walk hits a vertex in tree
188+
u = i
189+
while !in_tree[u]
190+
successors[u] = rand(rng, LG.neighbors(graph, u))
191+
u = successors[u]
192+
end
193+
# Erase loops formed during the walk
194+
u = i
195+
while !in_tree[u]
196+
in_tree[u] = true
197+
u = successors[u]
198+
end
199+
end
200+
201+
return directed_forest_from_successors(successors)
202+
end
203+
204+
function _generate_sample_rooted_spanning_forest_wilson(
205+
graph::LG.SimpleGraph{T},
206+
roots
207+
)::LG.SimpleDiGraph{T} where {T}
208+
return _generate_sample_rooted_spanning_forest_wilson(Random.default_rng(), graph, roots)
209+
end
210+
211+
"""
212+
directed_forest_from_successors(successors)::LG.SimpleDiGraph
213+
214+
Return a directed graph of size `length(successors)` with edges `i => successors[i]`.
215+
"""
216+
function directed_forest_from_successors(successors)::LG.SimpleDiGraph
217+
graph = LG.SimpleDiGraph(length(successors))
218+
for (i, j) in enumerate(successors)
219+
LG.add_edge!(graph, i, j)
220+
end
221+
return graph
222+
end

0 commit comments

Comments
 (0)