Current section

Files

Jump to
yog src yog@generator@classic.erl
Raw

src/yog@generator@classic.erl

-module(yog@generator@classic).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/yog/generator/classic.gleam").
-export([complete_with_type/2, complete/1, cycle_with_type/2, cycle/1, path_with_type/2, path/1, star_with_type/2, star/1, wheel_with_type/2, wheel/1, complete_bipartite_with_type/3, complete_bipartite/2, empty_with_type/2, empty/1, grid_2d_with_type/3, grid_2d/2, petersen_with_type/1, petersen/0, binary_tree_with_type/2, binary_tree/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Deterministic graph generators for common graph structures.\n"
"\n"
" Deterministic generators produce identical graphs given the same parameters,\n"
" useful for testing algorithms, benchmarking, and creating known structures.\n"
"\n"
" ## Available Generators\n"
"\n"
" | Generator | Graph Type | Complexity | Edges |\n"
" |-----------|------------|------------|-------|\n"
" | `complete` | K_n | O(n²) | n(n-1)/2 |\n"
" | `cycle` | C_n | O(n) | n |\n"
" | `path` | P_n | O(n) | n-1 |\n"
" | `star` | S_n | O(n) | n-1 |\n"
" | `wheel` | W_n | O(n) | 2(n-1) |\n"
" | `grid_2d` | Lattice | O(mn) | (m-1)n + m(n-1) |\n"
" | `complete_bipartite` | K_{m,n} | O(mn) | mn |\n"
" | `binary_tree` | Tree | O(2^d) | 2^(d+1) - 2 |\n"
" | `petersen` | Petersen | O(1) | 15 |\n"
" | `empty` | Isolated | O(n) | 0 |\n"
"\n"
" ## Quick Start\n"
"\n"
" ```gleam\n"
" import yog/generator/classic\n"
" import yog/model\n"
"\n"
" pub fn main() {\n"
" // Classic structures\n"
" let cycle = classic.cycle(5) // C5 cycle graph\n"
" let complete = classic.complete(4) // K4 complete graph\n"
" let grid = classic.grid_2d(3, 4) // 3x4 lattice mesh\n"
" let tree = classic.binary_tree(3) // Depth-3 binary tree\n"
" let bipartite = classic.complete_bipartite(3, 4) // K_{3,4}\n"
" let petersen = classic.petersen() // Famous Petersen graph\n"
" }\n"
" ```\n"
"\n"
" ## Use Cases\n"
"\n"
" - **Algorithm testing**: Verify correctness on known structures\n"
" - **Benchmarking**: Compare performance across standard graphs\n"
" - **Network modeling**: Represent specific topologies (star, grid, tree)\n"
" - **Graph theory**: Study properties of well-known graphs\n"
"\n"
" ## References\n"
"\n"
" - [Wikipedia: Graph Generators](https://en.wikipedia.org/wiki/Graph_theory#Graph_generators)\n"
" - [Complete Graph](https://en.wikipedia.org/wiki/Complete_graph)\n"
" - [Cycle Graph](https://en.wikipedia.org/wiki/Cycle_graph)\n"
" - [Petersen Graph](https://en.wikipedia.org/wiki/Petersen_graph)\n"
" - [NetworkX Generators](https://networkx.org/documentation/stable/reference/generators.html)\n"
).
-file("src/yog/generator/classic.gleam", 531).
-spec create_nodes(yog@model:graph(nil, RMM), integer()) -> yog@model:graph(nil, RMM).
create_nodes(Graph, N) ->
_pipe = yog@internal@utils:range(0, N - 1),
gleam@list:fold(
_pipe,
Graph,
fun(G, I) -> yog@model:add_node(G, I, nil) end
).
-file("src/yog/generator/classic.gleam", 87).
?DOC(
" Generates a complete graph with specified graph type.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let directed_k4 = generate.complete_with_type(4, model.Directed)\n"
" ```\n"
).
-spec complete_with_type(integer(), yog@model:graph_type()) -> yog@model:graph(nil, integer()).
complete_with_type(N, Graph_type) ->
Graph = create_nodes(yog@model:new(Graph_type), N),
case Graph_type of
undirected ->
_pipe = yog@internal@utils:range(0, N - 1),
gleam@list:fold(
_pipe,
Graph,
fun(G, I) -> _pipe@1 = yog@internal@utils:range(I + 1, N - 1),
gleam@list:fold(
_pipe@1,
G,
fun(Acc, J) ->
yog@model:add_edge_ensure(Acc, I, J, 1, nil)
end
) end
);
directed ->
_pipe@2 = yog@internal@utils:range(0, N - 1),
gleam@list:fold(
_pipe@2,
Graph,
fun(G@1, I@1) -> _pipe@3 = yog@internal@utils:range(0, N - 1),
gleam@list:fold(
_pipe@3,
G@1,
fun(Acc@1, J@1) -> case I@1 =:= J@1 of
true ->
Acc@1;
false ->
yog@model:add_edge_ensure(
Acc@1,
I@1,
J@1,
1,
nil
)
end end
) end
)
end.
-file("src/yog/generator/classic.gleam", 76).
?DOC(
" Generates a complete graph K_n where every node connects to every other.\n"
"\n"
" In a complete graph with n nodes, there are n(n-1)/2 edges for undirected\n"
" graphs and n(n-1) edges for directed graphs. All edges have unit weight (1).\n"
"\n"
" **Time Complexity:** O(n²)\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let k5 = classic.complete(5)\n"
" // K5 has 5 nodes and 10 edges\n"
" ```\n"
"\n"
" ## Use Cases\n"
"\n"
" - Testing algorithms on dense graphs\n"
" - Maximum connectivity scenarios\n"
" - Clique detection benchmarks\n"
).
-spec complete(integer()) -> yog@model:graph(nil, integer()).
complete(N) ->
complete_with_type(N, undirected).
-file("src/yog/generator/classic.gleam", 145).
?DOC(" Generates a cycle graph with specified graph type.\n").
-spec cycle_with_type(integer(), yog@model:graph_type()) -> yog@model:graph(nil, integer()).
cycle_with_type(N, Graph_type) ->
case N < 3 of
true ->
yog@model:new(Graph_type);
false ->
Graph = create_nodes(yog@model:new(Graph_type), N),
_pipe = yog@internal@utils:range(0, N - 1),
gleam@list:fold(
_pipe,
Graph,
fun(G, I) ->
Next = case I =:= (N - 1) of
true ->
0;
false ->
I + 1
end,
yog@model:add_edge_ensure(G, I, Next, 1, nil)
end
)
end.
-file("src/yog/generator/classic.gleam", 140).
?DOC(
" Generates a cycle graph C_n where nodes form a ring.\n"
"\n"
" A cycle graph connects n nodes in a circular pattern:\n"
" 0 -> 1 -> 2 -> ... -> (n-1) -> 0. Each node has degree 2.\n"
"\n"
" Returns an empty graph if n < 3 (cycles require at least 3 nodes).\n"
"\n"
" **Time Complexity:** O(n)\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let c6 = classic.cycle(6)\n"
" // C6: 0-1-2-3-4-5-0 (a hexagon)\n"
" ```\n"
"\n"
" ## Use Cases\n"
"\n"
" - Ring network topologies\n"
" - Circular dependency testing\n"
" - Hamiltonian cycle benchmarks\n"
).
-spec cycle(integer()) -> yog@model:graph(nil, integer()).
cycle(N) ->
cycle_with_type(N, undirected).
-file("src/yog/generator/classic.gleam", 178).
?DOC(" Generates a path graph with specified graph type.\n").
-spec path_with_type(integer(), yog@model:graph_type()) -> yog@model:graph(nil, integer()).
path_with_type(N, Graph_type) ->
case N < 2 of
true ->
create_nodes(yog@model:new(Graph_type), N);
false ->
Graph = create_nodes(yog@model:new(Graph_type), N),
_pipe = yog@internal@utils:range(0, N - 2),
gleam@list:fold(
_pipe,
Graph,
fun(G, I) -> yog@model:add_edge_ensure(G, I, I + 1, 1, nil) end
)
end.
-file("src/yog/generator/classic.gleam", 173).
?DOC(
" Generates a path graph P_n where nodes form a linear chain.\n"
"\n"
" **Time Complexity:** O(n)\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let p5 = classic.path(5)\n"
" ```\n"
).
-spec path(integer()) -> yog@model:graph(nil, integer()).
path(N) ->
path_with_type(N, undirected).
-file("src/yog/generator/classic.gleam", 209).
?DOC(" Generates a star graph with specified graph type.\n").
-spec star_with_type(integer(), yog@model:graph_type()) -> yog@model:graph(nil, integer()).
star_with_type(N, Graph_type) ->
case N < 2 of
true ->
create_nodes(yog@model:new(Graph_type), N);
false ->
Graph = create_nodes(yog@model:new(Graph_type), N),
_pipe = yog@internal@utils:range(1, N - 1),
gleam@list:fold(
_pipe,
Graph,
fun(G, I) -> yog@model:add_edge_ensure(G, 0, I, 1, nil) end
)
end.
-file("src/yog/generator/classic.gleam", 204).
?DOC(
" Generates a star graph where one central node is connected to all others.\n"
"\n"
" Node 0 is the center, connected to nodes 1 through n-1. All edges have unit weight (1).\n"
"\n"
" **Time Complexity:** O(n)\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let s6 = classic.star(6)\n"
" ```\n"
).
-spec star(integer()) -> yog@model:graph(nil, integer()).
star(N) ->
star_with_type(N, undirected).
-file("src/yog/generator/classic.gleam", 250).
?DOC(" Generates a wheel graph with specified graph type.\n").
-spec wheel_with_type(integer(), yog@model:graph_type()) -> yog@model:graph(nil, integer()).
wheel_with_type(N, Graph_type) ->
case N < 4 of
true ->
yog@model:new(Graph_type);
false ->
With_star = star_with_type(N, Graph_type),
_pipe = yog@internal@utils:range(1, N - 1),
gleam@list:fold(
_pipe,
With_star,
fun(G, I) ->
Next = case I =:= (N - 1) of
true ->
1;
false ->
I + 1
end,
yog@model:add_edge_ensure(G, I, Next, 1, nil)
end
)
end.
-file("src/yog/generator/classic.gleam", 245).
?DOC(
" Generates a wheel graph: a cycle with a central hub.\n"
"\n"
" A wheel graph combines a star and a cycle: node 0 is the hub,\n"
" and nodes 1..(n-1) form a cycle.\n"
"\n"
" Returns an empty graph if n < 4 (wheels require at least 4 nodes).\n"
"\n"
" **Time Complexity:** O(n)\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let w6 = classic.wheel(6)\n"
" // W6: hub 0 connected to cycle 1-2-3-4-5-1\n"
" ```\n"
"\n"
" ## Use Cases\n"
"\n"
" - Hybrid network topologies\n"
" - Fault-tolerant network design\n"
" - Routing algorithm benchmarks\n"
).
-spec wheel(integer()) -> yog@model:graph(nil, integer()).
wheel(N) ->
wheel_with_type(N, undirected).
-file("src/yog/generator/classic.gleam", 295).
?DOC(" Generates a complete bipartite graph with specified graph type.\n").
-spec complete_bipartite_with_type(integer(), integer(), yog@model:graph_type()) -> yog@model:graph(nil, integer()).
complete_bipartite_with_type(M, N, Graph_type) ->
Total = M + N,
Graph = create_nodes(yog@model:new(Graph_type), Total),
_pipe = yog@internal@utils:range(0, M - 1),
gleam@list:fold(
_pipe,
Graph,
fun(G, Left) -> _pipe@1 = yog@internal@utils:range(M, Total - 1),
gleam@list:fold(
_pipe@1,
G,
fun(Acc, Right) ->
yog@model:add_edge_ensure(Acc, Left, Right, 1, nil)
end
) end
).
-file("src/yog/generator/classic.gleam", 290).
?DOC(
" Generates a complete bipartite graph K_{m,n}.\n"
"\n"
" A complete bipartite graph has two disjoint sets of nodes (left and right partitions),\n"
" where every node in the left partition connects to every node in the right partition.\n"
" Left partition: nodes 0..(m-1), Right partition: nodes m..(m+n-1).\n"
"\n"
" **Time Complexity:** O(mn)\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let k33 = classic.complete_bipartite(3, 3)\n"
" // K_{3,3}: 3 nodes in each partition, 9 edges\n"
" ```\n"
"\n"
" ## Use Cases\n"
"\n"
" - Matching problems (job assignment, pairing)\n"
" - Bipartite graph algorithms\n"
" - Network flow modeling\n"
).
-spec complete_bipartite(integer(), integer()) -> yog@model:graph(nil, integer()).
complete_bipartite(M, N) ->
complete_bipartite_with_type(M, N, undirected).
-file("src/yog/generator/classic.gleam", 327).
?DOC(" Generates an empty graph with specified graph type.\n").
-spec empty_with_type(integer(), yog@model:graph_type()) -> yog@model:graph(nil, integer()).
empty_with_type(N, Graph_type) ->
create_nodes(yog@model:new(Graph_type), N).
-file("src/yog/generator/classic.gleam", 322).
?DOC(
" Generates an empty graph with n nodes and no edges.\n"
"\n"
" **Time Complexity:** O(n)\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let empty = classic.empty(10)\n"
" ```\n"
).
-spec empty(integer()) -> yog@model:graph(nil, integer()).
empty(N) ->
empty_with_type(N, undirected).
-file("src/yog/generator/classic.gleam", 431).
?DOC(" Generates a 2D grid graph with specified graph type.\n").
-spec grid_2d_with_type(integer(), integer(), yog@model:graph_type()) -> yog@model:graph(nil, integer()).
grid_2d_with_type(Rows, Cols, Graph_type) ->
N = Rows * Cols,
Graph = create_nodes(yog@model:new(Graph_type), N),
With_horizontal = begin
_pipe = yog@internal@utils:range(0, Rows - 1),
gleam@list:fold(
_pipe,
Graph,
fun(G, Row) -> _pipe@1 = yog@internal@utils:range(0, Cols - 2),
gleam@list:fold(
_pipe@1,
G,
fun(Acc, Col) ->
Node = (Row * Cols) + Col,
yog@model:add_edge_ensure(Acc, Node, Node + 1, 1, nil)
end
) end
)
end,
_pipe@2 = yog@internal@utils:range(0, Rows - 2),
gleam@list:fold(
_pipe@2,
With_horizontal,
fun(G@1, Row@1) -> _pipe@3 = yog@internal@utils:range(0, Cols - 1),
gleam@list:fold(
_pipe@3,
G@1,
fun(Acc@1, Col@1) ->
Node@1 = (Row@1 * Cols) + Col@1,
Below = Node@1 + Cols,
yog@model:add_edge_ensure(Acc@1, Node@1, Below, 1, nil)
end
) end
).
-file("src/yog/generator/classic.gleam", 426).
?DOC(
" Generates a 2D grid graph (lattice).\n"
"\n"
" Creates a rectangular grid where each node is connected to its\n"
" orthogonal neighbors (up, down, left, right). Nodes are numbered\n"
" row by row: node at (r, c) has ID = r * cols + c.\n"
"\n"
" **Time Complexity:** O(rows * cols)\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let grid = classic.grid_2d(3, 4)\n"
" // 3x4 grid with 12 nodes\n"
" // Node numbering: 0-1-2-3\n"
" // | | | |\n"
" // 4-5-6-7\n"
" // | | | |\n"
" // 8-9-10-11\n"
" ```\n"
"\n"
" ## Use Cases\n"
"\n"
" - Mesh network topologies\n"
" - Spatial/grid-based algorithms\n"
" - Image processing graph models\n"
" - Game board representations\n"
).
-spec grid_2d(integer(), integer()) -> yog@model:graph(nil, integer()).
grid_2d(Rows, Cols) ->
grid_2d_with_type(Rows, Cols, undirected).
-file("src/yog/generator/classic.gleam", 500).
?DOC(" Generates a Petersen graph with specified graph type.\n").
-spec petersen_with_type(yog@model:graph_type()) -> yog@model:graph(nil, integer()).
petersen_with_type(Graph_type) ->
Graph = create_nodes(yog@model:new(Graph_type), 10),
With_outer = begin
_pipe = Graph,
_pipe@1 = yog@model:add_edge_ensure(_pipe, 0, 1, 1, nil),
_pipe@2 = yog@model:add_edge_ensure(_pipe@1, 1, 2, 1, nil),
_pipe@3 = yog@model:add_edge_ensure(_pipe@2, 2, 3, 1, nil),
_pipe@4 = yog@model:add_edge_ensure(_pipe@3, 3, 4, 1, nil),
yog@model:add_edge_ensure(_pipe@4, 4, 0, 1, nil)
end,
With_inner = begin
_pipe@5 = With_outer,
_pipe@6 = yog@model:add_edge_ensure(_pipe@5, 5, 7, 1, nil),
_pipe@7 = yog@model:add_edge_ensure(_pipe@6, 7, 9, 1, nil),
_pipe@8 = yog@model:add_edge_ensure(_pipe@7, 9, 6, 1, nil),
_pipe@9 = yog@model:add_edge_ensure(_pipe@8, 6, 8, 1, nil),
yog@model:add_edge_ensure(_pipe@9, 8, 5, 1, nil)
end,
_pipe@10 = With_inner,
_pipe@11 = yog@model:add_edge_ensure(_pipe@10, 0, 5, 1, nil),
_pipe@12 = yog@model:add_edge_ensure(_pipe@11, 1, 6, 1, nil),
_pipe@13 = yog@model:add_edge_ensure(_pipe@12, 2, 7, 1, nil),
_pipe@14 = yog@model:add_edge_ensure(_pipe@13, 3, 8, 1, nil),
yog@model:add_edge_ensure(_pipe@14, 4, 9, 1, nil).
-file("src/yog/generator/classic.gleam", 495).
?DOC(
" Generates the Petersen graph.\n"
"\n"
" The [Petersen graph](https://en.wikipedia.org/wiki/Petersen_graph) is a famous\n"
" undirected graph with 10 nodes and 15 edges. It is often used as a counterexample\n"
" in graph theory due to its unique properties.\n"
"\n"
" **Time Complexity:** O(1)\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let petersen = classic.petersen()\n"
" // 10 nodes, 15 edges\n"
" ```\n"
"\n"
" ## Properties\n"
"\n"
" - 3-regular (every node has degree 3)\n"
" - Diameter 2\n"
" - Not planar\n"
" - Not Hamiltonian\n"
"\n"
" ## Use Cases\n"
"\n"
" - Graph theory counterexamples\n"
" - Algorithm testing\n"
" - Theoretical research\n"
).
-spec petersen() -> yog@model:graph(nil, integer()).
petersen() ->
petersen_with_type(undirected).
-file("src/yog/generator/classic.gleam", 541).
-spec do_power(integer(), integer(), integer()) -> integer().
do_power(Base, Exp, Acc) ->
case Exp of
0 ->
Acc;
_ ->
do_power(Base, Exp - 1, Acc * Base)
end.
-file("src/yog/generator/classic.gleam", 537).
-spec power(integer(), integer()) -> integer().
power(Base, Exp) ->
do_power(Base, Exp, 1).
-file("src/yog/generator/classic.gleam", 356).
?DOC(" Generates a complete binary tree with specified graph type.\n").
-spec binary_tree_with_type(integer(), yog@model:graph_type()) -> yog@model:graph(nil, integer()).
binary_tree_with_type(Depth, Graph_type) ->
case Depth < 0 of
true ->
yog@model:new(Graph_type);
false ->
N = power(2, Depth + 1) - 1,
Graph = create_nodes(yog@model:new(Graph_type), N),
_pipe = yog@internal@utils:range(0, N - 1),
gleam@list:fold(
_pipe,
Graph,
fun(G, I) ->
Left_child = (2 * I) + 1,
Right_child = (2 * I) + 2,
With_left = case Left_child < N of
true ->
yog@model:add_edge_ensure(G, I, Left_child, 1, nil);
false ->
G
end,
case Right_child < N of
true ->
yog@model:add_edge_ensure(
With_left,
I,
Right_child,
1,
nil
);
false ->
With_left
end
end
)
end.
-file("src/yog/generator/classic.gleam", 351).
?DOC(
" Generates a complete binary tree of given depth.\n"
"\n"
" Node 0 is the root. For node i: left child is 2i+1, right child is 2i+2.\n"
" Total nodes: 2^(depth+1) - 1. All edges have unit weight (1).\n"
"\n"
" **Time Complexity:** O(2^depth)\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let tree = classic.binary_tree(3)\n"
" // Complete binary tree with depth 3, total 15 nodes\n"
" ```\n"
"\n"
" ## Use Cases\n"
"\n"
" - Hierarchical structures\n"
" - Binary search tree modeling\n"
" - Heap data structure visualization\n"
" - Tournament brackets\n"
).
-spec binary_tree(integer()) -> yog@model:graph(nil, integer()).
binary_tree(Depth) ->
binary_tree_with_type(Depth, undirected).