Current section

Files

Jump to
yog_ex lib yog layout random.ex
Raw

lib/yog/layout/random.ex

defmodule Yog.Layout.Random do
@moduledoc """
Random layout algorithm for positioning graph nodes in Elixir.
Positions nodes uniformly at random within a 2D bounding box. This layout serves
as a baseline layout, an initialization method for iterative layout algorithms (such
as the Spring layout), or a test benchmark.
## Mathematical Model
Given a bounding box with width $W$, height $H$, and center $(c_x, c_y)$, the coordinates
for each node $i$ are generated as:
$$x_i \\sim U\\left(c_x - \\frac{W}{2}, c_x + \\frac{W}{2}\\right)$$
$$y_i \\sim U\\left(c_y - \\frac{H}{2}, c_y + \\frac{H}{2}\\right)$$
where $U(a, b)$ is the uniform distribution.
## Complexities
* **Time Complexity:** $O(V)$ where $V$ is the number of nodes.
* **Space Complexity:** $O(V)$ auxiliary space to allocate the coordinates map.
"""
alias Yog.Graph
@doc """
Positions nodes randomly within a specified bounding box.
## Options
* `:width` - The width of the bounding box (default: `1.0`).
* `:height` - The height of the bounding box (default: `1.0`).
* `:center` - The `{x, y}` coordinates of the center of the bounding box (default: `{0.0, 0.0}`).
* `:seed` - Optional integer seed or term for reproducible random positioning.
## Examples
iex> graph = Yog.undirected() |> Yog.add_nodes_from([1, 2, 3])
iex> pos = Yog.Layout.Random.layout(graph)
iex> Map.keys(pos) |> Enum.sort()
[1, 2, 3]
"""
@spec layout(Graph.t(), keyword()) :: %{Graph.node_id() => {float(), float()}}
def layout(graph, opts \\ []) do
width = Keyword.get(opts, :width, 1.0)
height = Keyword.get(opts, :height, 1.0)
{cx, cy} = Keyword.get(opts, :center, {0.0, 0.0})
seed = Keyword.get(opts, :seed)
if seed do
:rand.seed(:exsss, seed)
end
nodes = Yog.all_nodes(graph)
min_x = cx - width / 2.0
min_y = cy - height / 2.0
Map.new(nodes, fn node_id ->
x = min_x + :rand.uniform() * width
y = min_y + :rand.uniform() * height
{node_id, {x, y}}
end)
end
end