Metrics#

The measurements of one stage, each paired with its difference from the baseline. Project.Evaluate returns them in EvaluateResult.Baseline, in CandidateResult.Scheduled, and inside LeveledMetrics.Metrics for the leveled stage. In the baseline's own Metrics, every delta is 0.

Declaration#

namespace Plen;

public sealed class Metrics : IDeepCloneable<Metrics>, IEquatable<Metrics>

Treat a returned Metrics as read-only; call DeepClone() before changing it.

Properties#

Property Type Description
Finish Finish Project finish and the finish of each focus task. required.
Overload Overload Resource overload of the stage, in total, per resource and per focus task. required.
Conflicts Amount Number of entries in the stage's Conflicts list.
Cycles Amount Number of entries in the stage's Cycles list. Greater than 0 when the candidate made the plan cyclic.
Cost double Score of the stage. Lower is better.

Cost is computed from the other properties by one fixed formula:

Cost = max(0, Finish.Project.Delta)
     + Overload.Total.Value
     + 1000 × (Conflicts.Value + Cycles.Value)

The 1000 × penalty ranks every stage with conflicts or cycles after every stage without them. To rank by another rule, compare the raw properties instead of Cost.

Methods#

DeepClone#

public Metrics DeepClone()

Returns a deep copy. Finish, Overload and every list in them are copied.

Equals#

public bool Equals(Metrics? other)

Value equality: nested objects and lists compare element by element, double values by ==. GetHashCode is consistent with it.

ToString#

public override string ToString()

Returns a readable rendering of every property, for logging.

Finish#

Finish dates of the stage: the project and each task listed in EvaluateOptions.Focus.

public sealed class Finish : IDeepCloneable<Finish>, IEquatable<Finish>
Property Type Description
Project Shift? Latest end over the stage's scheduled tasks. null when the project has no tasks. Its Delta is measured on the global calendar and is 0 when the baseline has no tasks.
Tasks List<TaskFinish> One entry per focus task, in Focus order. Empty when Focus is empty.

TaskFinish#

The finish of one focus task.

public sealed class TaskFinish : IDeepCloneable<TaskFinish>, IEquatable<TaskFinish>
Property Type Description
Id Id The focus task. required.
Finish Shift? The task's finish. null when the candidate removed the task. Its Delta is measured on the task's calendar.

Shift#

A finish date and how far it moved from the baseline finish.

public sealed class Shift : IDeepCloneable<Shift>, IEquatable<Shift>
Property Type Description
Date Moment The finish date in this stage.
Delta double Working time from the baseline finish to Date, in SchedulingConfig.DurationUnit. Positive when the stage finishes later.

Finish, TaskFinish and Shift have the same DeepClone, Equals and ToString members as Metrics.

Example#

Score a two-day extension of task 1 and read how far the project finish moves.

using Plen;

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

var data = new ProjectData
{
    Tasks = [new TaskData(1) { StartDate = monday, Duration = 3.0 }],
};

var project = new Project();
project.Solve(data, new SolveOptions());

var changes = new SchedulingChanges();
changes.Tasks.Update.Add(new TaskUpdate { Id = 1, Duration = 5.0 });

var result = project.Evaluate(
    [new Candidate { Id = "longer", Changes = changes }],
    new EvaluateOptions { Focus = [1] });

var metrics = result.Candidates[0].Scheduled;
if (metrics?.Finish.Project is { } finish)
    Console.WriteLine($"finish {finish.Date}, {finish.Delta:+0.##;-0.##;0} days, cost {metrics.Cost}");