GanttEx.CriticalPath (GanttEx v0.1.0)

Copy Markdown View Source

Critical path and slack analysis (CPM) of the current plan.

A backward pass computes, for each schedulable task, the latest dates it can have without delaying its successors or the end of the project:

  • total slack - how much the task can slip without delaying the project end (late start - start)
  • free slack - how much the task can slip without delaying any successor
  • a task is critical when its total slack is zero (or negative, when the plan already breaks a dependency); a project is critical when one of its descendants is
  • a link is critical when it joins two critical tasks and drives the successor (the successor starts exactly when the link allows)

Slack is expressed in the duration unit of the store and honors calendars.

iex> store = GanttEx.Store.new!(
...>   [
...>     %{id: 1, text: "Design", start_date: ~D[2025-01-06], duration: 2},
...>     %{id: 2, text: "Build", start_date: ~D[2025-01-08], duration: 3},
...>     %{id: 3, text: "Docs", start_date: ~D[2025-01-08], duration: 1},
...>     %{id: 4, text: "Launch", start_date: ~D[2025-01-11], type: :milestone}
...>   ],
...>   [
...>     %{id: 1, source: 1, target: 2},
...>     %{id: 2, source: 1, target: 3},
...>     %{id: 3, source: 2, target: 4},
...>     %{id: 4, source: 3, target: 4}
...>   ]
...> )
iex> analysis = GanttEx.CriticalPath.analyze(store)
iex> for id <- 1..4, do: {id, analysis.tasks[id].critical, analysis.tasks[id].total_slack}
[{1, true, 0}, {2, true, 0}, {3, false, 2}, {4, true, 0}]
iex> analysis.tasks[3].free_slack
2
iex> analysis.links |> Enum.sort()
[1, 3]

Summary

Types

t()

Analysis of one task.

Functions

Analyzes the store. Projects with children get critical (and the slack of their most critical descendant).

Types

t()

@type t() :: %{
  tasks: %{required(GanttEx.Task.id()) => task_result()},
  links: MapSet.t(GanttEx.Task.id()),
  project_end: NaiveDateTime.t() | nil
}

task_result()

@type task_result() :: %{
  critical: boolean(),
  total_slack: integer(),
  free_slack: integer(),
  late_start: NaiveDateTime.t(),
  late_finish: NaiveDateTime.t()
}

Analysis of one task.

Functions

analyze(store)

@spec analyze(GanttEx.Store.t()) :: t()

Analyzes the store. Projects with children get critical (and the slack of their most critical descendant).