Yog.Property.Structure (YogEx v0.97.1)

Copy Markdown View Source

Structural properties of graphs.

This module provides checks for various graph classes and regularities.

Algorithms

ProblemFunctionComplexity
Tree checktree?/1O(V + E)
Arborescence checkarborescence?/1O(V + E)
Forest checkforest?/1O(V + E)
Branching checkbranching?/1O(V + E)
Complete graph checkcomplete?/1O(V)
Regular graph checkregular?/2O(V)
Connected checkconnected?/1O(V + E)
Strongly connected checkstrongly_connected?/1O(V + E)
Weakly connected checkweakly_connected?/1O(V + E)
Chordal checkchordal?/1O(V + E)

Key Concepts

  • Tree: Connected acyclic undirected graph.
  • Arborescence: Directed tree with a unique root.
  • Complete Graph (Kn): Every pair of distinct vertices is connected by an edge.
  • Regular Graph: Every vertex has the same degree k.

Structural Visualizations

Comparison of an undirected tree and a complete graph.

graph G { rankdir=LR; bgcolor="transparent"; node [shape=circle, fontname="inherit"]; edge [fontname="inherit", fontsize=10]; subgraph cluster_tree { label="Undirected Tree"; color="#6366f1"; style=rounded; T1 -- T2; T1 -- T3; T2 -- T4; T2 -- T5; } subgraph cluster_complete { label="Complete (K3)"; color="#f43f5e"; style=rounded; K1 -- K2; K2 -- K3; K3 -- K1; } }
iex> alias Yog.Property.Structure
iex> tree = Yog.from_edges(:undirected, [{"T1", "T2", 1}, {"T1", "T3", 1}, {"T2", "T4", 1}, {"T2", "T5", 1}])
iex> Structure.tree?(tree)
true
iex> complete = Yog.from_edges(:undirected, [{"K1", "K2", 1}, {"K2", "K3", 1}, {"K3", "K1", 1}])
iex> Structure.complete?(complete)
true

Arborescence Visualization

A directed tree with a unique root node.

digraph G { rankdir=TB; bgcolor="transparent"; node [shape=circle, fontname="inherit"]; edge [fontname="inherit", fontsize=10]; subgraph cluster_arb { label="Arborescence"; color="#10b981"; style=rounded; R -> A; R -> B; A -> C; A -> D; } }
iex> alias Yog.Property.Structure
iex> arb = Yog.from_edges(:directed, [{"R", "A", 1}, {"R", "B", 1}, {"A", "C", 1}, {"A", "D", 1}])
iex> Structure.arborescence?(arb)
true
iex> Structure.arborescence_root(arb)
"R"

Examples

# Simple tree
iex> graph = Yog.undirected()
...> |> Yog.add_node(1, nil)
...> |> Yog.add_node(2, nil)
...> |> Yog.add_edge_ensure(1, 2, 1)
iex> Yog.Property.Structure.tree?(graph)
true

# Complete graph K3 (triangle)
iex> graph = Yog.undirected() |> Yog.add_node(1, nil) |> Yog.add_node(2, nil) |> Yog.add_node(3, nil)
...> |> Yog.add_edge_ensure(1, 2, 1) |> Yog.add_edge_ensure(2, 3, 1) |> Yog.add_edge_ensure(3, 1, 1)
iex> Yog.Property.Structure.complete?(graph)
true

Summary

Functions

Checks if the graph is an arborescence (directed tree with a single root).

Finds the root of an arborescence.

Checks if a directed graph is a branching (a directed forest).

Checks if the graph is chordal using Maximum Cardinality Search.

Checks if the graph is complete (every pair of distinct nodes is connected).

Checks if the graph is connected.

Checks if the graph is a forest (a loopless undirected graph consisting entirely of disjoint trees).

Returns the minimum degree of the graph.

Checks if the graph is k-regular (every node has degree exactly k).

Checks if a directed graph is strongly connected.

Checks if the graph is a tree (connected and acyclic). Works for undirected graphs.

Checks if a directed graph is weakly connected.

Functions

arborescence?(graph)

@spec arborescence?(Yog.graph()) :: boolean()

Checks if the graph is an arborescence (directed tree with a single root).

A directed graph is an arborescence iff:

  • It has n nodes and n-1 edges
  • Exactly one node has in-degree 0 (the root)
  • All other nodes have in-degree >= 1

When edges = n-1 and there's exactly one root, reachability is guaranteed (no need for explicit BFS check).

arborescence_root(graph)

@spec arborescence_root(Yog.graph()) :: Yog.node_id() | nil

Finds the root of an arborescence.

branching?(graph)

@spec branching?(Yog.graph()) :: boolean()

Checks if a directed graph is a branching (a directed forest).

Evaluates to true if every node has an in-degree of 1 or 0, and the graph contains no directed cycles.

Examples

iex> branch = Yog.directed()
...> |> Yog.add_edge_ensure(1, 2, 1, nil)
...> |> Yog.add_edge_ensure(1, 3, 1, nil)
...> |> Yog.add_edge_ensure(4, 5, 1, nil)
iex> Yog.Property.Structure.branching?(branch)
true

chordal?(graph)

@spec chordal?(Yog.graph()) :: boolean()

Checks if the graph is chordal using Maximum Cardinality Search.

complete?(graph)

@spec complete?(Yog.graph()) :: boolean()

Checks if the graph is complete (every pair of distinct nodes is connected).

connected?(graph)

@spec connected?(Yog.graph()) :: boolean()

Checks if the graph is connected.

For undirected graphs, every node is reachable from every other node. For directed graphs, this checks for strong connectivity.

forest?(graph)

@spec forest?(Yog.graph()) :: boolean()

Checks if the graph is a forest (a loopless undirected graph consisting entirely of disjoint trees).

A disconnected graph with multiple trees evaluates to true.

Examples

iex> forest = Yog.undirected()
...> |> Yog.add_edge_ensure(1, 2, 1, nil)
...> |> Yog.add_edge_ensure(3, 4, 1, nil)
iex> Yog.Property.Structure.forest?(forest)
true

minimum_degree(graph)

@spec minimum_degree(Yog.graph()) :: non_neg_integer()

Returns the minimum degree of the graph.

Isolated vertices have degree 0. Returns 0 for an empty graph.

Examples

iex> graph = Yog.from_edges(:undirected, [{1, 2, 1}, {2, 3, 1}])
iex> Yog.Property.Structure.minimum_degree(graph)
1

iex> empty = Yog.undirected()
iex> Yog.Property.Structure.minimum_degree(empty)
0

regular?(graph, k)

@spec regular?(Yog.graph(), integer()) :: boolean()

Checks if the graph is k-regular (every node has degree exactly k).

strongly_connected?(graph)

@spec strongly_connected?(Yog.graph()) :: boolean()

Checks if a directed graph is strongly connected.

tree?(graph)

@spec tree?(Yog.graph()) :: boolean()

Checks if the graph is a tree (connected and acyclic). Works for undirected graphs.

Time Complexity

O(V + E)

weakly_connected?(graph)

@spec weakly_connected?(Yog.graph()) :: boolean()

Checks if a directed graph is weakly connected.