JuliaGraphs / JuliaGraphs/Graphs.jl
Iterator for self-avoiding walks
Nobody has claimed this yet.
- Dominant language
- Julia
- Stars
- 538
- Forks
- 128
- Avg merge
- 10h 25m
- Merged PRs (30d)
- 2
Description
I happened to need an iterator of all self-avoiding walks from a start to a destination. I didn't see something like this mentioned in the docs, although there was a random self-avoiding walks generator. Maybe I missed something or this is in another package. Anyway, I wrote up some code for it, and it's below in case that's something people are interested in.
struct PathIterator{Graph}
graph::Graph
origin::Int
destination::Int
end
function eltype(::Type{<: PathIterator})
Vector{Int}
end
function IteratorSize(::Type{<: PathIterator})
SizeUnknown()
end
struct PathState
path::Vector{Int}
visited::Set{Int}
decisions::Vector{Tuple{Vector{Int}, Int}}
end
function PathState(;
path = Int[],
visited = Set{Int}(),
decisions = Tuple{Vector{Int}, Int}[]
)
PathState(path, visited, decisions)
end
function add_path_vertex!(path_state, vertex)
push!(path_state.path, vertex)
push!(path_state.visited, vertex)
end
function choose!(path_state, choices, chosen)
push!(path_state.decisions, (choices, chosen))
vertex = choices[chosen]
add_path_vertex!(path_state, vertex)
vertex
end
function find_choices(path_iterator, path_state, cursor)
setdiff(outneighbors(path_iterator.graph, cursor), path_state.visited)
end
function forwards!(path_iterator, path_state, cursor)
path = path_state.path
destination = path_iterator.destination
while cursor !== nothing
if cursor === destination
return copy(path), path_state
end
choices = find_choices(path_iterator, path_state, cursor)
while !(isempty(choices))
cursor = choose!(path_state, choices, 1)
if cursor === destination
return copy(path), path_state
end
choices = find_choices(path_iterator, path_state, cursor)
end
cursor = backwards!(path_iterator, path_state)
end
return nothing
end
function backwards_one!(path_state)
old_vertex = pop!(path_state.path)
delete!(path_state.visited, old_vertex)
pop!(path_state.decisions)
end
function backwards!(path_iterator, path_state)
decisions = path_state.decisions
if isempty(decisions)
return nothing
end
(choices, old_chosen) = backwards_one!(path_state)
while old_chosen == length(choices)
if isempty(decisions)
return nothing
end
(choices, old_chosen) = backwards_one!(path_state)
end
cursor = choose!(path_state, choices, old_chosen + 1)
end
function iterate(path_iterator::PathIterator)
path_state = PathState()
origin = path_iterator.origin
add_path_vertex!(path_state, origin)
forwards!(path_iterator, path_state, origin)
end
function iterate(path_iterator::PathIterator, path_state::PathState)
cursor = backwards!(path_iterator, path_state)
forwards!(path_iterator, path_state, cursor)
end
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
The issue names no repository file or test; start by comparing the proposed PathIterator with the existing random self-avoiding walks generator and the package's iterator conventions. Done means maintainers have agreed on the API and scope, with the iterator and its documentation integrated accordingly.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- julia
- Domain
- data
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100