package tsort

  1. Overview
  2. Docs
Easy to use and user-friendly topological sort

Install

Dune Dependency

Authors

Maintainers

Sources

2.2.0.tar.gz
md5=efe0d2a972638bd07a65b30fed372ed2
sha512=162fbeff69a34f00439570f5fbe3112f2ef6d9cf423a9a3c6a7ad1707cc35b6cb19e0bfa1e70c35c12b8a7adfc70a5aca5a43bef63c7f63aca53b396277019b8

Description

Easy to use and user-friendly topological sort.

Example:

Tsort.sort [("foundation", []); ("walls", ["foundation"]); ("roof", ["walls"])]

Published: 02 Apr 2025

README

ocaml-tsort CircleCI badge"

ocaml-tsort is a library for sorting graphs in topological order. Its UI/UX is inspired by the classic UNIX tsort(1).

  • Uses Kahn's algorithm.
  • Easy to use, but not very fast.
  • Provides friendly error reporting (e.g., if there's a cycle, tells you what the offending nodes are).

The input type is (('a * 'a list) list). Essentially, a list of "tasks" mapped to lists of their dependencies.

Sorting DAGs

Most of the time cyclic dependencies are bad. The main function, Tsort.sort returns value of this type:

type 'a sort_result =
  Sorted of 'a list 
| ErrorCycle of 'a list

The function is:

val sort : ('a * 'a list) list -> 'a sort_result

Examples:

# Tsort.sort [
  ("foundation", []);
  ("walls", ["foundation"]);
  ("roof", ["walls"])
] ;;
- : string Tsort.sort_result = Tsort.Sorted ["foundation"; "walls"; "roof"]

# Tsort.sort [
  ("foundation", ["building permit"]);
  ("walls", ["foundation"]);
  ("roof", ["walls"])
] ;;
- : string Tsort.sort_result =
Tsort.Sorted ["building permit"; "foundation"; "walls"; "roof"]

# Tsort.sort [
  ("foundation", ["roof"]);
  ("walls", ["foundation"]);
  ("roof", ["walls"])
] ;;
- : string Tsort.sort_result = Tsort.ErrorCycle ["roof"; "foundation"; "walls"]

As you can see from the second example, if there's a dependency on a node that doesn't exist in the input, it's automatically inserted, and assumed to have no dependencies.

Detecting non-existent dependencies

If your graph comes directly from user input, there's a good chance that dependency on a non-existent node is a user error.

To prevent it, use Tsort.find_nonexistent_nodes. Example:

# Tsort.find_nonexistent_nodes [
  ("foundation", ["building permit"]);
  ("walls", ["foundation"]);
  ("roof", ["walls"])] ;;
- : (string * string list) list = [("foundation", ["building permit"])]

Sorting graphs with cycles

Sometimes cycles are fine. In this case you can use Tsort.sort_strongly_connected_components to split your graph into strongly connected components and sort its condensation.

Contrived example: suppose you want to line up the Addams family so that children come after parents, but spouse and sibling pairs are not separated.

Tsort.sort_strongly_connected_components [
  "Morticia",  ["Gomez"; "Grandmama"];
  "Gomez",     ["Morticia"; "Grandmama"];
  "Wednesday", ["Morticia"; "Gomez"; "Pugsley"];
  "Pugsley",   ["Morticia"; "Gomez"; "Wednesday"];
  "Grandmama", [];
  "Fester",    []
]
;;

- : string list list =
[["Fester"]; ["Grandmama"]; ["Morticia"; "Gomez"]; ["Wednesday"; "Pugsley"]]

There's also Tsort.find_strongly_connected_components if you just want to find what them. For the data above, it would return [["Morticia"; "Gomez"]; ["Wednesday"; "Pugsley"]; ["Grandmama"]; ["Fester"]].

Contributing

To run our complete test suite, run make test-complete (requires docker).

Dependencies (2)

  1. dune >= "1.9"
  2. ocaml >= "4.03.0"

Dev Dependencies (1)

  1. alcotest with-test

Used by (4)

  1. dkml-install
  2. dscheck >= "0.2.0"
  3. sihl >= "1.0.0~rc3"
  4. soupault >= "1.12.0"

Conflicts

None

OCaml

Innovation. Community. Security.