[Canonical page](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/analytics/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# Analytics

Critical path and slack computed over a schedule's dates. It's the `Analytics` property of [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/schedule-result.md>). That property is set only when the call's [`AnalyticsOptions`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/analytics-options.md>) set `CriticalPath`, `Slack`, or both. With both `false`, it's `null`.

## Declaration

```csharp
namespace Plen;

public sealed class Analytics : IDeepCloneable<Analytics>, IEquatable<Analytics>
{
    public AnalyticsStatus Status { get; set; }
    public Critical? CriticalPath { get; set; }
    public List<TaskSlack>? Slack { get; set; }

    public Analytics DeepClone();
    public bool Equals(Analytics? other);
}
```

## Properties

| Property | Type | Description |
|---|---|---|
| `Status` | [`AnalyticsStatus`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/analytics.md#analyticsstatus>) | Whether the analytics could be computed. |
| `CriticalPath` | [`Critical`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/analytics.md#critical>)`?` | Critical tasks and links. Set when [`AnalyticsOptions.CriticalPath`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/analytics-options.md>) is `true` and `Status` is `Available`; `null` otherwise. |
| `Slack` | `List<`[`TaskSlack`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/analytics.md#taskslack>)`>?` | Total and free slack per task. Set when `AnalyticsOptions.Slack` is `true` and `Status` is `Available`; `null` otherwise. |

With `Status` set to `AnalyticsStatus.Invalid`, both `CriticalPath` and `Slack` are `null`, whatever the options asked for. Check `Status` before reading the other properties.

## Methods

### DeepClone

```csharp
public Analytics DeepClone()
```

Returns a copy that shares no list or nested object with this one.

### Equals

```csharp
public bool Equals(Analytics? other)
public override bool Equals(object? obj)
```

Value equality: `Status` is equal, `CriticalPath` is equal or both `null`, and `Slack` is equal element by element or both `null`. `GetHashCode` is consistent with it.

### ToString

```csharp
public override string ToString()
```

Returns a readable dump of all properties, for logging.

## AnalyticsStatus

Whether [`Analytics`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/analytics.md#analytics>) could be computed.

```csharp
public enum AnalyticsStatus
{
    Available,
    Invalid,
}
```

| Value | Description |
|---|---|
| `Available` | Analytics were computed. The requested properties are set. |
| `Invalid` | The dependency graph has a cycle. `CriticalPath` and `Slack` are `null`. |

## Critical

The critical tasks and links of a schedule.

```csharp
public sealed class Critical : IDeepCloneable<Critical>, IEquatable<Critical>
{
    public List<Id> Tasks { get; set; } = [];
    public List<Id> Links { get; set; } = [];
}
```

| Property | Type | Description |
|---|---|---|
| `Tasks` | `List<`[`Id`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/id.md>)`>` | Ids of the critical tasks. A summary is listed when one of its non-summary descendants is critical. Completed tasks are never listed. |
| `Links` | `List<`[`Id`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/id.md>)`>` | Ids of the links between critical tasks that leave no margin. |

`Critical` has value equality (both lists compared element by element), `DeepClone()` and `ToString()`, like `Analytics`.

## TaskSlack

Total and free slack of one task. Entries exist for active leaf tasks and milestones; summaries have none.

```csharp
public sealed class TaskSlack : IDeepCloneable<TaskSlack>, IEquatable<TaskSlack>
{
    public required Id Task { get; set; }
    public double Total { get; set; }
    public double Free { get; set; }
}
```

| Property | Type | Description |
|---|---|---|
| `Task` | [`Id`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/id.md>) | Id of the task. Required. |
| `Total` | `double` | Total slack, in the configured [`SchedulingConfig.DurationUnit`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/scheduling-config.md>). `0` for a completed task. |
| `Free` | `double` | Free slack, in the same unit. `0` for a completed task. |

`TaskSlack` has value equality (`Total` and `Free` compared with `==`), `DeepClone()` and `ToString()`, like `Analytics`.

## Example

Requests the critical path and slack for three tasks and prints both:

```csharp
using Plen;

var monday = Moment.FromYmdHm(2026, 1, 5, 8, 0)
    ?? throw new InvalidOperationException("invalid date");

var data = new ProjectData
{
    Tasks =
    [
        new TaskData("design") { StartDate = monday, Duration = 2.0 },
        new TaskData("build") { StartDate = monday, Duration = 3.0 },
        new TaskData("docs") { StartDate = monday, Duration = 1.0 },
    ],
    Links =
    [
        new LinkData { Id = "l1", Source = "design", Target = "build" },
    ],
};

var options = new SolveOptions
{
    Analytics = new AnalyticsOptions { CriticalPath = true, Slack = true },
};

var analytics = new Project().Solve(data, options).Analytics
    ?? throw new InvalidOperationException("analytics not requested");

if (analytics.Status == AnalyticsStatus.Invalid)
{
    Console.WriteLine("the dependency graph has a cycle");
    return;
}

if (analytics.CriticalPath is { } critical)
    Console.WriteLine($"critical tasks: {string.Join(", ", critical.Tasks)}");

foreach (var s in analytics.Slack ?? [])
    Console.WriteLine($"{s.Task}: total {s.Total}, free {s.Free}");
```

## Related

- [`AnalyticsOptions`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/analytics-options.md>) - requests the critical path and slack
- [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/schedule-result.md#analytics>) - the result that carries `Analytics`
- [`Project.Analyze`](<https://docs.dhtmlx.com/planning-engine/net/api/project-analyze.md>) - analytics over current or supplied dates without rescheduling
- [Critical path and slack](<https://docs.dhtmlx.com/planning-engine/net/scheduling/critical-path-and-slack.md>) - how slack and the critical path are computed and used
