Powered by AppSignal & Oban Pro

Gallery: Graph Catalog

livebooks/gallery/graph_catalog.livemd

Gallery: Graph Catalog

Mix.install([
  {:yog_ex, "~> 0.98"},
  {:kino_vizjs, "~> 0.8.0"}
])

Introduction

This gallery showcases the wide variety of graph structures that Yog can generate out-of-the-box. Whether you need a standard deterministic structure for benchmarking or a complex random network for simulation, the Yog.Generator suite has you covered.

Setup

defmodule CatalogHelper do
  def render_tabs(graph, label \\ nil) do
    if label do
      IO.puts("#{label} — Nodes: #{Yog.node_count(graph)}, Edges: #{Yog.edge_count(graph)}")
    else
      IO.puts("Nodes: #{Yog.node_count(graph)}, Edges: #{Yog.edge_count(graph)}")
    end

    dot_source = Yog.Render.DOT.to_dot(graph)
    mermaid_source = Yog.Render.Mermaid.to_mermaid(graph)

    Kino.Layout.tabs([
      "Dot": Kino.VizJS.render(dot_source, height: "500px"),
      "Mermaid": Kino.Mermaid.new(mermaid_source)
    ])
  end

  def render_tabs_with_opts(graph, opts, label \\ nil) do
    if label do
      IO.puts("#{label} — Nodes: #{Yog.node_count(graph)}, Edges: #{Yog.edge_count(graph)}")
    else
      IO.puts("Nodes: #{Yog.node_count(graph)}, Edges: #{Yog.edge_count(graph)}")
    end

    dot_source = Yog.Render.DOT.to_dot(graph, opts)
    mermaid_source = Yog.Render.Mermaid.to_mermaid(graph)

    Kino.Layout.tabs([
      "Dot": Kino.VizJS.render(dot_source, height: "500px"),
      "Mermaid": Kino.Mermaid.new(mermaid_source)
    ])
  end
end

Classic Deterministic Graphs

These graphs are the building blocks of graph theory. They have predictable properties and are essential for testing algorithms.

The Famous Petersen Graph

A 3-regular graph with 10 nodes and 15 edges. It is a frequent counterexample in graph theory.

petersen = Yog.Generator.Classic.petersen()
CatalogHelper.render_tabs(petersen)

Complete Graphs ($K_n$)

Every node is connected to every other node.

k5 = Yog.Generator.Classic.complete(5)
CatalogHelper.render_tabs(k5)

Grid Graphs (2D Lattice)

Nodes arranged in a grid, connecting to their neighbors (up, down, left, right).

grid = Yog.Generator.Classic.grid_2d(4, 4)
CatalogHelper.render_tabs(grid)

Star and Wheel Graphs

A Star has one central hub, while a Wheel adds a cycle around the rim.

star = Yog.Generator.Classic.star(7)
wheel = Yog.Generator.Classic.wheel(7)

CatalogHelper.render_tabs(star, "Star")
CatalogHelper.render_tabs(wheel, "Wheel")

Binary Tree and Hypercube

# A perfect binary tree of depth 3
tree = Yog.Generator.Classic.binary_tree(3)

# A 4-dimensional hypercube (16 nodes, 32 edges)
hypercube = Yog.Generator.Classic.hypercube(4)

CatalogHelper.render_tabs(tree, "Binary Tree")
CatalogHelper.render_tabs(hypercube, "Hypercube")

Random Graph Models

Random graphs are used to model real-world phenomena like social networks, the internet, or biological systems.

Erdős-Rényi ($G(n, p)$)

Edges are created between any two nodes with a fixed probability $p$.

# 20 nodes, each edge has 15% chance of existing
er = Yog.Generator.Random.erdos_renyi_gnp(20, 0.15)
CatalogHelper.render_tabs(er)

Watts-Strogatz (Small World)

Starts with a regular ring lattice and then rewires edges to create “short cuts,” resulting in low average path length and high clustering.

# 20 nodes, each connected to 4 neighbors, 10% rewiring
ws = Yog.Generator.Random.watts_strogatz(20, 4, 0.1)
CatalogHelper.render_tabs(ws)

Barabási-Albert (Scale-Free)

Uses “preferential attachment” (the rich get richer) to create networks with power-law degree distributions—hubs are common.

# 30 nodes, each new node attaches to 2 existing ones
ba = Yog.Generator.Random.barabasi_albert(30, 2)
CatalogHelper.render_tabs(ba)

Stochastic Block Model (SBM)

Generates graphs with predefined community structures.

# 30 nodes total, 3 communities of 10 nodes each, p_in = 0.8, p_out = 0.05
g = Yog.Generator.Random.sbm(30, 3, 0.8, 0.05, community_sizes: [10, 10, 10])

# Color nodes by their planted community
opts = Yog.Render.DOT.community_to_options(%Yog.Community.Result{
  assignments: Map.new(0..9, &{&1, 0}) |> Map.merge(Map.new(10..19, &{&1, 1})) |> Map.merge(Map.new(20..29, &{&1, 2})),
  num_communities: 3,
  metadata: %{}
})
CatalogHelper.render_tabs_with_opts(g, opts)

Quick Property Checks

Every generated graph can be analyzed immediately.

# Pick any graph from above
g = Yog.Generator.Classic.petersen()

IO.inspect([
  node_count: Yog.node_count(g),
  edge_count: Yog.edge_count(g),
  is_regular: Yog.Property.Structure.regular?(g, 3),
  is_connected: Yog.Property.Structure.connected?(g),
  diameter: Yog.Health.diameter(g)
], label: "Petersen Properties")

Mermaid Rendering

All graphs can also be rendered as Mermaid diagrams for embedding in Markdown documents.

g = Yog.Generator.Classic.petersen()
mermaid = Yog.Render.Mermaid.to_mermaid(g, Yog.Render.Mermaid.theme(:minimal))

IO.puts(mermaid)
Kino.Mermaid.new(mermaid)

Summary

The Yog.Generator suite allows you to:

  1. Benchmarking: Test how your algorithms scale from sparse paths to dense cliques.
  2. Simulation: Model real-world networks using well-studied random models.
  3. Visualization: Quickly create complex structures to verify your rendering pipelines.

Check out the Algorithm Catalog to see how to analyze these graphs!