Current section
Files
Jump to
Current section
Files
lib/backfish/examples/hamiltonian_path.ex
defmodule Backfish.Examples.HamiltonianPath do
@moduledoc """
An implementation of the Hamiltonian path problem using the Backfish
backtracking library.
The Hamiltonian path problem involves finding a path in an undirected or
directed graph that visits each vertex exactly once.
"""
use Backfish.ProblemDefinition
@doc """
Returns the initial state of the Hamiltonian path problem.
## Parameters
- `args`: A keyword list of arguments. Expects `:graph`, which is a map
representing the graph where keys are nodes and values are lists of
adjacent nodes, and `:start_node`, which is the starting node for the
path.
## Returns
- A map representing the initial state, including the graph, the initial
path with the starting node, and a set of visited nodes.
"""
@impl true
def initial_state(args) do
graph = Keyword.get(args, :graph, %{})
start_node = Keyword.get(args, :start_node, nil)
%{graph: graph, path: [start_node], visited: MapSet.new([start_node])}
end
@doc """
Checks if the given state is a goal state.
## Parameters
- `state`: The current state of the problem, which includes the graph, the
path, and the set of visited nodes.
## Returns
- `true` if the number of visited nodes equals the number of nodes in the
graph, `false` otherwise.
"""
@impl true
def is_goal?(%{graph: graph, path: _path, visited: visited}) do
MapSet.size(visited) == map_size(graph)
end
@doc """
Generates the next possible states from the given state.
## Parameters
- `state`: The current state of the problem, which includes the graph, the
path, and the set of visited nodes.
## Returns
- A list of the next possible states, each including a new path with an
additional node visited.
"""
@impl true
def next_steps(%{graph: graph, path: path, visited: visited}) do
current_node = hd(path)
neighbors = Map.get(graph, current_node, [])
neighbors
|> Enum.filter(&(!MapSet.member?(visited, &1)))
|> Enum.map(fn neighbor ->
%{graph: graph, path: [neighbor | path], visited: MapSet.put(visited, neighbor)}
end)
end
end