# `GanttEx.CriticalPath`
[🔗](https://github.com/rocket4ce/gantt_ex/blob/v0.1.0/lib/gantt_ex/critical_path.ex#L1)

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]

# `t`

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

# `task_result`

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

Analysis of one task.

# `analyze`

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

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

---

*Consult [api-reference.md](api-reference.md) for complete listing*
