yog_io/tgf

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:

  1. Node section: Each line is node_id node_label
  2. Separator: A single # character on its own line
  3. Edge section: Each line is source_id target_id [edge_label]

Example

import yog/model.{Directed}
import yog_io/tgf

// Create a simple graph
let graph =
  model.new(Directed)
  |> model.add_node(1, "Alice")
  |> model.add_node(2, "Bob")

let assert Ok(graph) = model.add_edge(graph, from: 1, to: 2, with: "follows")

// Serialize to TGF
let tgf_string = tgf.serialize(graph)

// Write to file
let assert Ok(Nil) = tgf.write("graph.tgf", graph)

Output Format

1 Alice
2 Bob
#
1 2 follows

Characteristics

Parsing Behavior

When parsing TGF files, the following behaviors apply:

References

Types

Errors that can occur during TGF parsing.

pub type TgfError {
  EmptyInput
  InvalidNodeLine(line: Int, content: String)
  InvalidEdgeLine(line: Int, content: String)
  InvalidNodeId(line: Int, value: String)
  InvalidEdgeEndpoint(line: Int, value: String)
  DuplicateNodeId(line: Int, id: Int)
  ReadError(path: String, error: String)
  WriteError(path: String, error: String)
}

Constructors

  • EmptyInput

    Empty input string

  • InvalidNodeLine(line: Int, content: String)

    Invalid node line format

  • InvalidEdgeLine(line: Int, content: String)

    Invalid edge line format

  • InvalidNodeId(line: Int, value: String)

    Invalid node ID (not an integer)

  • InvalidEdgeEndpoint(line: Int, value: String)

    Invalid edge endpoint (not an integer)

  • DuplicateNodeId(line: Int, id: Int)

    Duplicate node ID encountered

  • ReadError(path: String, error: String)

    File read error

  • WriteError(path: String, error: String)

    File write error

Options for TGF serialization.

pub type TgfOptions(n, e) {
  TgfOptions(
    node_label: fn(n) -> String,
    edge_label: fn(e) -> option.Option(String),
  )
}

Constructors

  • TgfOptions(
      node_label: fn(n) -> String,
      edge_label: fn(e) -> option.Option(String),
    )

    Arguments

    node_label

    Function to convert node data to a label string

    edge_label

    Function to convert edge data to an optional label string Returns None for no label (just source and target)

Result type for TGF parsing.

pub type TgfResult(n, e) {
  TgfResult(
    graph: model.Graph(n, e),
    warnings: List(#(Int, String)),
  )
}

Constructors

  • TgfResult(
      graph: model.Graph(n, e),
      warnings: List(#(Int, String)),
    )

    Arguments

    warnings

    Lines that couldn’t be parsed (with line numbers)

Values

pub fn default_options() -> TgfOptions(String, String)

Default TGF serialization options.

Default configuration:

  • Node labels: Uses the node data’s string representation
  • Edge labels: None (edges are just source target)
pub fn options_with(
  node_label node_label: fn(n) -> String,
  edge_label edge_label: fn(e) -> option.Option(String),
) -> TgfOptions(n, e)

Creates TGF options with custom node and edge label functions.

Example

let options = tgf.options_with(
  node_label: fn(person) { person.name },
  edge_label: fn(weight) { Some(int.to_string(weight)) },
)
pub fn parse(
  input: String,
  gtype: model.GraphType,
) -> Result(TgfResult(String, String), TgfError)

Parses a TGF string into a graph with String labels.

Convenience function for the common case where both node and edge data are just Strings.

Example

let tgf_string = "1 Alice\n2 Bob\n#\n1 2 follows"

case tgf.parse(tgf_string, Directed) {
  Ok(result) -> {
    // result.graph is Graph(String, String)
    process_graph(result.graph)
  }
  Error(e) -> handle_error(e)
}
pub fn parse_with(
  input: String,
  graph_type gtype: model.GraphType,
  node_parser node_parser: fn(Int, String) -> n,
  edge_parser edge_parser: fn(String) -> e,
) -> Result(TgfResult(n, e), TgfError)

Parses a TGF string into a graph with custom parsers.

The graph type (directed/undirected) must be specified since TGF doesn’t encode this information.

Example

let tgf_string = "1 Alice\n2 Bob\n#\n1 2 follows"

let result = tgf.parse_with(
  tgf_string,
  graph_type: Directed,
  node_parser: fn(id, label) { label },
  edge_parser: fn(label) { label },
)

case result {
  Ok(tgf.TgfResult(graph, warnings)) -> {
    // Use the graph
    process_graph(graph)
  }
  Error(e) -> handle_error(e)
}
pub fn read(
  path: String,
  gtype: model.GraphType,
) -> Result(TgfResult(String, String), TgfError)

Reads a graph from a TGF file.

Convenience function that reads node and edge data as strings.

Example

let result = tgf.read("graph.tgf", Directed)

case result {
  Ok(tgf.TgfResult(graph, warnings)) -> {
    // Use the graph
    process_graph(graph)
  }
  Error(e) -> handle_error(e)
}
pub fn read_with(
  path: String,
  graph_type gtype: model.GraphType,
  node_parser node_parser: fn(Int, String) -> n,
  edge_parser edge_parser: fn(String) -> e,
) -> Result(TgfResult(n, e), TgfError)

Reads a graph from a TGF file with custom parsers.

Example

let result = tgf.read_with(
  "graph.tgf",
  graph_type: Directed,
  node_parser: fn(id, label) { Person(id, label) },
  edge_parser: fn(label) { String.to_int(label) },
)
pub fn serialize(graph: model.Graph(String, String)) -> String

Serializes a graph to TGF format.

Convenience function for graphs with String node and edge data.

Example

let tgf_string = tgf.serialize(graph)
pub fn serialize_with(
  options: TgfOptions(n, e),
  graph: model.Graph(n, e),
) -> String

Serializes a graph to TGF format with custom label functions.

This function allows you to control how node and edge data are converted to TGF labels.

Time Complexity: O(V + E)

Example

import yog/model.{Directed}
import yog_io/tgf

type Person {
  Person(name: String, age: Int)
}

let graph =
  model.new(Directed)
  |> model.add_node(1, Person("Alice", 30))
  |> model.add_node(2, Person("Bob", 25))
  |> model.add_edge(from: 1, to: 2, with: "follows")

let options = tgf.options_with(
  node_label: fn(p) { p.name },
  edge_label: fn(label) { Some(label) },
)

let tgf_string = tgf.serialize_with(options, graph)
pub fn to_string(graph: model.Graph(String, String)) -> String

Converts a graph to a TGF string.

Alias for serialize for consistency with other modules.

pub fn write(
  path: String,
  graph: model.Graph(String, String),
) -> Result(Nil, simplifile.FileError)

Writes a graph to a TGF file.

Example

let assert Ok(Nil) = tgf.write("graph.tgf", graph)
pub fn write_with(
  path: String,
  options: TgfOptions(n, e),
  graph: model.Graph(n, e),
) -> Result(Nil, simplifile.FileError)

Writes a graph to a TGF file with custom label functions.

Example

let options = tgf.options_with(
  node_label: fn(p) { p.name },
  edge_label: fn(w) { Some(int.to_string(w)) },
)

let assert Ok(Nil) = tgf.write_with("graph.tgf", options, graph)
Search Document