Current section
Files
Jump to
Current section
Files
lib/yog/dag.ex
defmodule Yog.DAG do
@moduledoc """
Directed Acyclic Graph (DAG) data structure.
A DAG is a wrapper around a `Yog.Graph` that guarantees acyclicity at the type level.
This enables total functions (functions that always succeed) for operations like
topological sorting that would be partial for general graphs.
## Examples
iex> graph = Yog.Graph.new(:directed)
iex> {:ok, dag} = Yog.DAG.from_graph(graph)
iex> is_struct(dag, Yog.DAG)
true
"""
@type t :: %__MODULE__{
graph: Yog.Graph.t()
}
@enforce_keys [:graph]
defstruct [:graph]
@doc """
Creates a new empty DAG.
"""
@spec new() :: t()
def new do
%__MODULE__{
graph: Yog.Graph.new(:directed)
}
end
@doc """
Attempts to create a DAG from a graph.
Validates that the graph is directed and contains no cycles.
"""
@spec from_graph(Yog.Graph.t()) :: {:ok, t()} | {:error, :cycle_detected}
def from_graph(%Yog.Graph{kind: :undirected}) do
{:error, :cycle_detected}
end
def from_graph(%Yog.Graph{} = graph) do
if Yog.Property.Cyclicity.acyclic?(graph) do
{:ok, %__MODULE__{graph: graph}}
else
{:error, :cycle_detected}
end
end
@doc """
Unwraps a DAG back into a regular Graph.
"""
@spec to_graph(t()) :: Yog.Graph.t()
def to_graph(%__MODULE__{graph: graph}), do: graph
end