Analytics#
Critical path and slack computed over a schedule's dates. It's the Analytics property of ScheduleResult. That property is set only when the call's AnalyticsOptions set CriticalPath, Slack, or both. With both false, it's null.
Declaration#
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 |
Whether the analytics could be computed. |
CriticalPath |
Critical? |
Critical tasks and links. Set when AnalyticsOptions.CriticalPath is true and Status is Available; null otherwise. |
Slack |
List<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#
public Analytics DeepClone()
Returns a copy that shares no list or nested object with this one.
Equals#
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#
public override string ToString()
Returns a readable dump of all properties, for logging.
AnalyticsStatus#
Whether Analytics could be computed.
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.
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> |
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> |
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.
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 |
Id of the task. Required. |
Total |
double |
Total slack, in the configured SchedulingConfig.DurationUnit. 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:
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- requests the critical path and slackScheduleResult- the result that carriesAnalyticsProject.Analyze- analytics over current or supplied dates without rescheduling- Critical path and slack - how slack and the critical path are computed and used