Trivial Graph Format (TGF) serialization support.
Provides functions to serialize and deserialize graphs in TGF format, a very simple text-based format suitable for quick graph exchange and debugging.
Format Overview
TGF consists of three parts:
- Node section: Each line is
node_id node_label - Separator: A single
#character on its own line - Edge section: Each line is
source_id target_id [edge_label]
Example
iex> graph = Yog.directed()
...> |> Yog.add_node(1, "Alice")
...> |> Yog.add_node(2, "Bob")
...> |> Yog.add_edge!(from: 1, to: 2, with: "follows")
iex>
iex> tgf_string = Yog.IO.TGF.serialize(graph)
iex> String.contains?(tgf_string, "1 Alice")
true
iex> String.contains?(tgf_string, "1 2")
trueParsing Behavior
When parsing TGF files, the following behaviors apply:
- Auto-node creation: If an edge references a node ID that was not declared in the node section, a node is automatically created with the ID as its label.
- Empty labels: Nodes without labels default to using their ID as the label.
- Malformed lines: Lines that cannot be parsed are skipped and collected
as warnings in the
TgfResult.
Summary
Functions
Returns default TGF serialization options.
Creates TGF options with custom node and edge label functions.
Parses a TGF string into a graph with String labels.
Parses a TGF string into a graph with custom parsers.
Reads a graph from a TGF file using String labels.
Reads a graph from a TGF file with custom parsers.
Serializes a graph to TGF format using default label conversion.
Serializes a graph to TGF format with custom label functions.
Writes a graph to a TGF file using default label conversion.
Writes a graph to a TGF file with custom label functions.
Functions
Returns default TGF serialization options.
Default behavior:
- Node labels: Convert data to string using
to_string/1 - Edge labels: No labels (returns
:none)
Example
iex> {:tgf_options, _node_fn, _edge_fn} = Yog.IO.TGF.default_options()
iex> :ok
:ok
Creates TGF options with custom node and edge label functions.
Time Complexity: O(1)
Parameters
node_label- Function to convert node data to string label(node_data) -> stringedge_label- Function to convert edge data to optional label(edge_data) -> :none | {:some, string}
Returns
TGF options tuple for use with serialize_with/2
Example
iex> options = Yog.IO.TGF.options_with(
...> fn data -> "Node: " <> to_string(data) end,
...> fn weight -> {:some, "W:" <> to_string(weight)} end
...> )
iex> {:tgf_options, _, _} = options
iex> :ok
:ok
Parses a TGF string into a graph with String labels.
Node and edge labels are stored as strings. For custom data structures,
use parse_with/4.
Time Complexity: O(V + E)
Parameters
input- TGF format stringgtype-:directedor:undirected
Returns
{:ok, {:tgf_result, graph, warnings}}on success{:error, reason}on parsing failure
The warnings list contains any malformed lines that were skipped.
Example
iex> tgf_string = """
...> 1 Alice
...> 2 Bob
...> #
...> 1 2 follows
...> """
iex> {:ok, {:tgf_result, graph, []}} = Yog.IO.TGF.parse(tgf_string, :directed)
iex> Yog.Model.node_count(graph)
2
Parses a TGF string into a graph with custom parsers.
This function allows you to transform TGF labels into custom Elixir data structures as the graph is built.
Time Complexity: O(V + E)
Parameters
input- TGF format stringgraph_type-:directedor:undirectednode_parser- Function to transform node label to node data(string) -> node_dataedge_parser- Function to transform edge label to edge data(string | nil) -> edge_data
Returns
{:ok, {:tgf_result, graph, warnings}}on success{:error, reason}on parsing failure
Example
tgf = "1 Alice\n2 Bob\n#\n1 2 5\n"
node_parser = fn label -> String.upcase(label) end
edge_parser = fn label ->
case label do
nil -> 1
val -> String.to_integer(val)
end
end
{:ok, {:tgf_result, graph, _warnings}} =
Yog.IO.TGF.parse_with(tgf, :directed, node_parser, edge_parser)
Reads a graph from a TGF file using String labels.
Time Complexity: O(V + E) + file I/O
Parameters
path- File path to read fromgtype-:directedor:undirected
Returns
{:ok, {:tgf_result, graph, warnings}}on success{:error, reason}on file read or parse failure
Example
{:ok, {:tgf_result, graph, warnings}} =
Yog.IO.TGF.read("network.tgf", :directed)
if warnings != [] do
IO.puts("Warning: Some lines were malformed")
end
Reads a graph from a TGF file with custom parsers.
Serializes a graph to TGF format using default label conversion.
Node data is converted to strings, edge labels are omitted.
Time Complexity: O(V + E)
Example
iex> graph = Yog.directed()
...> |> Yog.add_node(1, "Alice")
...> |> Yog.add_node(2, "Bob")
...> |> Yog.add_edge!(from: 1, to: 2, with: "follows")
iex> tgf = Yog.IO.TGF.serialize(graph)
iex> String.contains?(tgf, "1 Alice") and String.contains?(tgf, "1 2")
true
Serializes a graph to TGF format with custom label functions.
Allows full control over how node and edge data are converted to TGF labels.
Time Complexity: O(V + E) where V is nodes and E is edges
Parameters
options- TGF options tuple (seeoptions_with/2)graph- The graph to serialize
Returns
TGF format string
Example
iex> graph = Yog.directed()
...> |> Yog.add_node(1, %{name: "Alice"})
...> |> Yog.add_node(2, %{name: "Bob"})
...> |> Yog.add_edge!(from: 1, to: 2, with: 10)
iex> options = Yog.IO.TGF.options_with(
...> fn data -> data.name end,
...> fn weight -> {:some, Integer.to_string(weight)} end
...> )
iex> tgf_string = Yog.IO.TGF.serialize_with(options, graph)
iex> String.contains?(tgf_string, "1 Alice") and String.contains?(tgf_string, "1 2 10")
true
Writes a graph to a TGF file using default label conversion.
Time Complexity: O(V + E) + file I/O
Parameters
path- File path to write tograph- The graph to serialize
Returns
:okon success{:error, reason}on file write failure
Example
graph = Yog.directed()
|> Yog.add_node(1, "Alice")
|> Yog.add_node(2, "Bob")
|> Yog.add_edge!(from: 1, to: 2, with: "follows")
Yog.IO.TGF.write("network.tgf", graph)
# => :ok
Writes a graph to a TGF file with custom label functions.
Time Complexity: O(V + E) + file I/O
Parameters
path- File path to write tooptions- TGF options tuple (seeoptions_with/2)graph- The graph to serialize
Returns
:okon success{:error, reason}on file write failure
Example
graph = Yog.directed() |> Yog.add_node(1, %{name: "Alice"})
options = Yog.IO.TGF.options_with(fn d -> d.name end, fn _ -> :none end)
Yog.IO.TGF.write_with("network.tgf", options, graph)