Yog.IO.Pajek (YogEx v1.0.0)

Copy Markdown View Source

Pajek (.net) format serialization support.

Provides functions to serialize and deserialize graphs in the Pajek .net format, a standard format for social network analysis used by the Pajek software and compatible with many network analysis tools.

Format Overview

Pajek files have a structured text format with distinct sections:

  • Vertices: *Vertices N followed by node definitions
  • Arcs: *Arcs section for directed edges
  • Edges: *Edges section for undirected edges

Example

iex> graph = Yog.directed()
...> |> Yog.add_node(1, "Alice")
...> |> Yog.add_node(2, "Bob")
...> |> Yog.add_edge_ensure(from: 1, to: 2, with: "5")
iex>
iex> pajek_string = Yog.IO.Pajek.serialize(graph)
iex> String.contains?(pajek_string, "*Vertices 2")
true
iex> String.contains?(pajek_string, "\"Alice\"")
true

Default Configurations

To handle visual parameters like shapes, pass options via options_with.

Summary

Functions

Returns default node attributes with no special visualization.

Returns default Pajek options for String node and edge data.

Creates Pajek options with custom configurations for visualizations and labels.

Parses a Pajek string into a graph with String labels.

Parses a Pajek string into a graph with custom parser options.

Reads a graph from a Pajek file using String labels.

Reads a graph from a Pajek file with custom parsers.

Serializes a graph to Pajek format using default string conversion.

Serializes a graph to Pajek format with custom options.

Writes a graph to a Pajek file using default string conversion.

Writes a graph to a Pajek file with custom options.

Functions

default_node_attributes()

@spec default_node_attributes() :: tuple()

Returns default node attributes with no special visualization.

Node attributes control visual properties like shape, color, and coordinates in Pajek visualizations.

Example

iex> {:node_attributes, _, _, _, _, _} = Yog.IO.Pajek.default_node_attributes()
iex> :ok
:ok

default_options()

@spec default_options() :: tuple()

Returns default Pajek options for String node and edge data.

Default behavior:

  • Node labels: Convert data to string
  • Edge weights: No weights (returns :none)
  • Node attributes: No special visualization
  • Coordinates: Not included
  • Visuals: Not included
  • Node formatter: Kernel.to_string/1
  • Edge formatter: Kernel.to_string/1

Example

iex> {:pajek_options, _, _, _, _, _, _, _} = Yog.IO.Pajek.default_options()
iex> :ok
:ok

options_with(node_label, edge_weight, node_attributes, include_coordinates, include_visuals, opts \\ [])

@spec options_with(
  (any() -> any()),
  (any() -> any()),
  (any() -> any()),
  boolean(),
  boolean(),
  keyword()
) :: tuple()

Creates Pajek options with custom configurations for visualizations and labels.

Raises ArgumentError if function parameters, booleans, or keyword options are invalid.

Time complexity: $\mathcal{O}(1)$

Parameters

  • node_label - Function to convert node data to string label (node_data) -> string
  • edge_weight - Function to convert edge data to optional weight (edge_data) -> :none | {:some, number}
  • node_attributes - Function to generate visual attributes per node (node_data) -> node_attributes
  • include_coordinates - Whether to include x, y, z coordinates
  • include_visuals - Whether to include shape, color, etc.

Returns

Pajek options tuple for use with serialize_with/2

Example

options = Yog.IO.Pajek.options_with(
  fn data -> data.name end,                    # Node label
  fn weight -> {:some, weight} end,            # Edge weight
  fn _ -> Yog.IO.Pajek.default_node_attributes() end,  # No visuals
  false,                                       # No coordinates
  false                                        # No visuals
)

parse(input)

@spec parse(String.t()) ::
  {:ok, {:pajek_result, Yog.graph(), list()}} | {:error, term()}

Parses a Pajek string into a graph with String labels.

Node labels are stored as strings, edge weights as numbers. For custom data structures, use parse_with/3.

Raises ArgumentError if input is not a binary string.

Time complexity: $\mathcal{O}(V + E)$

Parameters

  • input - Pajek format string

Returns

  • {:ok, {:pajek_result, graph, warnings}} on success
  • {:error, reason} on parsing failure

Example

iex> input = "*Vertices 2\n1 \"Alice\"\n2 \"Bob\"\n*Arcs\n1 2"
iex> {:ok, {:pajek_result, graph, _warnings}} = Yog.IO.Pajek.parse(input)
iex> Yog.Model.node_count(graph)
2

parse_with(input, node_parser, edge_parser)

@spec parse_with(String.t(), (any() -> any()), (any() -> any())) ::
  {:ok, {:pajek_result, Yog.graph(), list()}} | {:error, term()}

Parses a Pajek string into a graph with custom parser options.

This function allows you to transform Pajek data into custom Elixir data structures as the graph is built.

Raises ArgumentError if input is not a binary string or parsers are invalid.

Time complexity: $\mathcal{O}(V + E)$

Parameters

  • input - Pajek format string
  • node_parser - Function to transform node label to node data (string) -> node_data
  • edge_parser - Function to transform edge weight to edge data (number | nil) -> edge_data

Returns

  • {:ok, {:pajek_result, graph, warnings}} on success
  • {:error, reason} on parsing failure

The warnings list contains any issues encountered during parsing.

Example

pajek_str = "*Vertices 2\n1 \"Alice\"\n2 \"Bob\"\n*Arcs\n1 2 5"

node_parser = fn label -> String.upcase(label) end
edge_parser = fn weight -> weight || 1 end

{:ok, {:pajek_result, graph, _warnings}} =
  Yog.IO.Pajek.parse_with(pajek_str, node_parser, edge_parser)

read(path)

@spec read(String.t()) ::
  {:ok, {:pajek_result, Yog.graph(), list()}} | {:error, term()}

Reads a graph from a Pajek file using String labels.

Raises ArgumentError if path is not a binary string.

Time complexity: $\mathcal{O}(V + E)$ + file I/O

Parameters

  • path - File path to read from (typically .net extension)

Returns

  • {:ok, {:pajek_result, graph, warnings}} on success
  • {:error, reason} on file read or parse failure

Example

{:ok, {:pajek_result, graph, warnings}} =
  Yog.IO.Pajek.read("network.net")

IO.puts("Loaded #{Yog.Model.node_count(graph)} nodes")

read_with(path, node_parser, edge_parser)

@spec read_with(String.t(), (any() -> any()), (any() -> any())) ::
  {:ok, {:pajek_result, Yog.graph(), list()}} | {:error, term()}

Reads a graph from a Pajek file with custom parsers.

Raises ArgumentError if path is not a binary string.

Time complexity: $\mathcal{O}(V + E)$ + file I/O

Parameters

  • path - File path to read from
  • node_parser - Function to transform node label to node data
  • edge_parser - Function to transform edge weight to edge data

Returns

  • {:ok, {:pajek_result, graph, warnings}} on success
  • {:error, reason} on file read or parse failure

Example

node_parser = fn label -> %{name: label} end
edge_parser = fn weight -> weight || 1 end

{:ok, {:pajek_result, graph, _warnings}} =
  Yog.IO.Pajek.read_with("network.net", node_parser, edge_parser)

serialize(graph)

@spec serialize(Yog.graph() | Yog.DAG.t()) :: String.t()

Serializes a graph to Pajek format using default string conversion.

Node data is converted to strings, edge weights are omitted.

Raises ArgumentError if graph is invalid.

Time complexity: $\mathcal{O}(V + E)$

Example

iex> graph = Yog.directed()
...> |> Yog.add_node(1, "Alice")
...> |> Yog.add_node(2, "Bob")
...> |> Yog.add_edge_ensure(from: 1, to: 2, with: "5")
iex> pajek = Yog.IO.Pajek.serialize(graph)
iex> String.contains?(pajek, "*Vertices 2") and String.contains?(pajek, ~s("Alice"))
true

serialize_with(options, graph)

@spec serialize_with(tuple(), Yog.graph() | Yog.DAG.t()) :: String.t()

Serializes a graph to Pajek format with custom options.

Allows full control over labels, weights, and visualization attributes.

Raises ArgumentError if graph or options are invalid.

Time complexity: $\mathcal{O}(V + E)$ where $V$ is node count and $E$ is edge count.

Parameters

  • options - Pajek options tuple (see options_with/6)
  • graph - The graph to serialize

Returns

Pajek format string

Example

graph = Yog.directed()
|> Yog.add_node(1, %{name: "Alice"})
|> Yog.add_node(2, %{name: "Bob"})
|> Yog.add_edge_ensure(from: 1, to: 2, with: 5)

options = Yog.IO.Pajek.options_with(
  fn data -> data.name end,
  fn weight -> {:some, weight} end,
  fn _ -> Yog.IO.Pajek.default_node_attributes() end,
  false, false
)

pajek = Yog.IO.Pajek.serialize_with(options, graph)

to_string(graph)

@spec to_string(Yog.graph() | Yog.DAG.t()) :: String.t()

Alias for serialize/1.

Provided for compatibility with other serialization libraries.

Time complexity: $\mathcal{O}(V + E)$

write(path, graph)

@spec write(String.t(), Yog.graph() | Yog.DAG.t()) :: :ok | {:error, atom()}

Writes a graph to a Pajek file using default string conversion.

Raises ArgumentError if path is not a binary string or graph is invalid.

Time complexity: $\mathcal{O}(V + E)$ + file I/O

Parameters

  • path - File path to write to (typically .net extension)
  • graph - The graph to serialize

Returns

  • :ok on success
  • {:error, reason} on file write failure

Example

graph = Yog.directed()
|> Yog.add_node(1, "Alice")
|> Yog.add_node(2, "Bob")
|> Yog.add_edge_ensure(from: 1, to: 2, with: "follows")

Yog.IO.Pajek.write("network.net", graph)
# => :ok

write_with(path, options, graph)

@spec write_with(String.t(), tuple(), Yog.graph() | Yog.DAG.t()) ::
  :ok | {:error, atom()}

Writes a graph to a Pajek file with custom options.

Raises ArgumentError if path is not a binary string or options/graph are invalid.

Time complexity: $\mathcal{O}(V + E)$ + file I/O

Parameters

  • path - File path to write to (typically .net extension)
  • options - Pajek options tuple (see options_with/6)
  • graph - The graph to serialize

Returns

  • :ok on success
  • {:error, reason} on file write failure

Example

graph = Yog.directed() |> Yog.add_node(1, %{name: "Alice"})
options = Yog.IO.Pajek.options_with(
  fn d -> d.name end, fn _ -> :none end,
  fn _ -> Yog.IO.Pajek.default_node_attributes() end,
  false, false
)

Yog.IO.Pajek.write_with("network.net", options, graph)