Yog.Builder.Labeled (YogEx v0.70.0)

Copy Markdown View Source

Build graphs using arbitrary labels instead of integer IDs.

This module provides a convenient way to build graphs when your nodes are naturally identified by strings, atoms, or other types, rather than integers.

Example Usage

# Build a graph with string labels
builder = Yog.Builder.Labeled.directed()
  |> Yog.Builder.Labeled.add_edge("home", "work", 10)
  |> Yog.Builder.Labeled.add_edge("work", "gym", 5)

# Convert to a Graph to use with algorithms
graph = Yog.Builder.Labeled.to_graph(builder)

# Get the node ID for a label
{:ok, home_id} = Yog.Builder.Labeled.get_id(builder, "home")

# Use with pathfinding
case Yog.Pathfinding.Dijkstra.shortest_path(
  in: graph,
  from: home_id,
  to: gym_id,
  zero: 0,
  add: &Kernel.+/2,
  compare: &Integer.compare/2
) do
  {:some, path} -> path
  :none -> :no_path
end

Batch Construction

For building from existing data, use the from_list functions:

edges = [{"A", "B", 5}, {"B", "C", 3}, {"A", "C", 10}]
builder = Yog.Builder.Labeled.from_list(:directed, edges)
graph = Yog.Builder.Labeled.to_graph(builder)

Migration Note: This module was ported from Gleam to pure Elixir in v0.53.0. The API remains unchanged.

Summary

Types

Legacy builder type (deprecated)

Any type can be used as a label

t()

Labeled builder struct

Functions

Adds an edge between two labeled nodes with a weight.

Adds a node with the given label.

Adds a simple edge with weight 1 between two labeled nodes.

Adds an unweighted edge between two labeled nodes.

Returns all labels that have been added to the builder.

Creates a new labeled directed graph builder.

Gets or creates a node for the given label.

Creates a builder from a list of labeled edges.

Creates a builder from a list of unweighted labeled edges.

Looks up the internal node ID for a given label.

Creates a new labeled graph builder of the specified type.

Gets the next available node ID.

Gets the predecessors of a node by its label.

Gets the successors of a node by its label.

Converts the builder to a standard Graph.

Gets the label-to-ID registry as a map.

Creates a new labeled undirected graph builder.

Types

builder()

@type builder() ::
  {:labeled_builder, Yog.Model.graph_type(), Yog.graph(), map(), integer()}
  | t()

Legacy builder type (deprecated)

label()

@type label() :: term()

Any type can be used as a label

t()

@type t() :: %Yog.Builder.Labeled{
  graph: Yog.graph(),
  kind: Yog.Model.graph_type(),
  label_to_id: %{required(label()) => Yog.node_id()},
  next_id: integer()
}

Labeled builder struct

Functions

add_edge(builder, from, to, weight)

@spec add_edge(t(), label(), label(), term()) :: t()

Adds an edge between two labeled nodes with a weight.

If either node doesn't exist, it will be created automatically.

Examples

iex> builder = Yog.Builder.Labeled.directed()
...> |> Yog.Builder.Labeled.add_edge("A", "B", 10)
iex> {:ok, successors} = Yog.Builder.Labeled.successors(builder, "A")
iex> successors
[{"B", 10}]

add_node(builder, label)

@spec add_node(t(), label()) :: t()

Adds a node with the given label.

Examples

iex> builder = Yog.Builder.Labeled.directed()
...> |> Yog.Builder.Labeled.add_node("Node A")
iex> Yog.Builder.Labeled.all_labels(builder)
["Node A"]

add_simple_edge(builder, from, to)

@spec add_simple_edge(t(), label(), label()) :: t()

Adds a simple edge with weight 1 between two labeled nodes.

Unlike add_unweighted_edge/3 which stores weight as nil, this stores weight as 1.

Examples

iex> builder = Yog.Builder.Labeled.directed()
...> |> Yog.Builder.Labeled.add_simple_edge("A", "B")
iex> is_struct(builder, Yog.Builder.Labeled)
true

add_unweighted_edge(builder, from, to)

@spec add_unweighted_edge(t(), label(), label()) :: t()

Adds an unweighted edge between two labeled nodes.

Examples

iex> builder = Yog.Builder.Labeled.directed()
...> |> Yog.Builder.Labeled.add_unweighted_edge("A", "B")
iex> {:ok, [{"B", nil}]} = Yog.Builder.Labeled.successors(builder, "A")

all_labels(arg1)

@spec all_labels(t() | builder()) :: [label()]

Returns all labels that have been added to the builder.

Examples

iex> builder = Yog.Builder.Labeled.directed()
...> |> Yog.Builder.Labeled.add_node("A")
...> |> Yog.Builder.Labeled.add_node("B")
iex> Yog.Builder.Labeled.all_labels(builder)
["A", "B"]

directed()

@spec directed() :: t()

Creates a new labeled directed graph builder.

Examples

iex> builder = Yog.Builder.Labeled.directed()
iex> is_struct(builder, Yog.Builder.Labeled)
true

ensure_node(builder, label)

@spec ensure_node(t(), label()) :: {t(), Yog.node_id()}

Gets or creates a node for the given label.

If a node with this label already exists, returns its existing ID. If it doesn't exist, creates a new node and returns the new ID.

Examples

iex> builder = Yog.Builder.Labeled.directed()
iex> {_builder, id} = Yog.Builder.Labeled.ensure_node(builder, "A")
iex> is_integer(id)
true

from_list(graph_type, edges)

@spec from_list(Yog.Model.graph_type(), [{label(), label(), term()}]) :: t()

Creates a builder from a list of labeled edges.

Examples

iex> edges = [{"A", "B", 5}, {"B", "C", 3}]
iex> builder = Yog.Builder.Labeled.from_list(:directed, edges)
iex> {:ok, [{"B", 5}]} = Yog.Builder.Labeled.successors(builder, "A")

from_unweighted_list(graph_type, edges)

@spec from_unweighted_list(Yog.Model.graph_type(), [{label(), label()}]) :: t()

Creates a builder from a list of unweighted labeled edges.

Examples

iex> edges = [{"A", "B"}, {"B", "C"}]
iex> builder = Yog.Builder.Labeled.from_unweighted_list(:directed, edges)
iex> {:ok, [{"B", nil}]} = Yog.Builder.Labeled.successors(builder, "A")

get_id(arg1, label)

@spec get_id(t() | builder(), label()) :: {:ok, Yog.node_id()} | {:error, nil}

Looks up the internal node ID for a given label.

Returns {:ok, id} if the label exists, {:error, nil} otherwise.

Examples

iex> builder = Yog.Builder.Labeled.directed()
...> |> Yog.Builder.Labeled.add_node("A")
iex> Yog.Builder.Labeled.get_id(builder, "A")
{:ok, 0}

iex> builder = Yog.Builder.Labeled.directed()
iex> Yog.Builder.Labeled.get_id(builder, "NonExistent")
{:error, nil}

new(graph_type)

@spec new(Yog.Model.graph_type()) :: t()

Creates a new labeled graph builder of the specified type.

Examples

iex> builder = Yog.Builder.Labeled.new(:directed)
iex> is_struct(builder, Yog.Builder.Labeled)
true

next_id(arg1)

@spec next_id(t() | builder()) :: Yog.node_id()

Gets the next available node ID.

This is the ID that would be assigned to the next new node.

Examples

iex> builder = Yog.Builder.Labeled.directed()
iex> Yog.Builder.Labeled.next_id(builder)
0
iex> builder = Yog.Builder.Labeled.add_node(builder, "A")
iex> Yog.Builder.Labeled.next_id(builder)
1

predecessors(arg1, label)

@spec predecessors(t() | builder(), label()) ::
  {:ok, [{label(), term()}]} | {:error, nil}

Gets the predecessors of a node by its label.

Returns {:ok, edges} where edges is a list of {label, weight} tuples, or {:error, nil} if the label doesn't exist.

Examples

iex> builder = Yog.Builder.Labeled.directed()
...> |> Yog.Builder.Labeled.add_edge("A", "B", 5)
iex> Yog.Builder.Labeled.predecessors(builder, "B")
{:ok, [{"A", 5}]}

successors(arg1, label)

@spec successors(t() | builder(), label()) ::
  {:ok, [{label(), term()}]} | {:error, nil}

Gets the successors of a node by its label.

Returns {:ok, edges} where edges is a list of {label, weight} tuples, or {:error, nil} if the label doesn't exist.

Examples

iex> builder = Yog.Builder.Labeled.directed()
...> |> Yog.Builder.Labeled.add_edge("A", "B", 10)
iex> Yog.Builder.Labeled.successors(builder, "A")
{:ok, [{"B", 10}]}

to_graph(arg1)

@spec to_graph(t() | builder()) :: Yog.graph()

Converts the builder to a standard Graph.

The resulting graph can be used with all Yog algorithms.

Examples

iex> builder = Yog.Builder.Labeled.directed()
...> |> Yog.Builder.Labeled.add_edge("A", "B", 5)
iex> graph = Yog.Builder.Labeled.to_graph(builder)
iex> Yog.graph?(graph)
true

to_registry(arg1)

@spec to_registry(t() | builder()) :: %{required(label()) => Yog.node_id()}

Gets the label-to-ID registry as a map.

Returns a map where keys are labels and values are node IDs.

Examples

iex> builder = Yog.Builder.Labeled.directed()
...> |> Yog.Builder.Labeled.add_node("A")
iex> registry = Yog.Builder.Labeled.to_registry(builder)
iex> Map.get(registry, "A")
0

undirected()

@spec undirected() :: t()

Creates a new labeled undirected graph builder.

Examples

iex> builder = Yog.Builder.Labeled.undirected()
iex> is_struct(builder, Yog.Builder.Labeled)
true