LevelingResult#

The outcome of a leveling run: the leveled schedule and how many rounds proposed a correction. Project.Level returns it.

Declaration#

namespace Plen;

public sealed class LevelingResult : IDeepCloneable<LevelingResult>, IEquatable<LevelingResult>
{
    public required ScheduleResult Schedule { get; set; }
    public uint Rounds { get; set; }

    public LevelingResult DeepClone();
    public bool Equals(LevelingResult? other);
}

Properties#

Property Type Description
Schedule ScheduleResult The schedule Level accepted as the new baseline.
Rounds uint Number of leveling rounds that proposed a correction.

Schedule#

public required ScheduleResult Schedule { get; set; }

The final solved state after leveling. Its BaselineId is the accepted baseline.

Its Updates are diffed against the state the Level call started from. Entries include the LevelingDelay and Pauses values leveling set. Windows left in Overallocations carry a Reason.

The project keeps this object as its baseline and shares it with clones. Treat it as read-only, or call DeepClone() on it before changing it. For the meaning of every field, see ScheduleResult.

Rounds#

public uint Rounds { get; set; }

Counts only rounds that proposed a delay or a pause. It's 0 when nothing needed leveling, and when the project is cyclic: then Schedule is the initial solve's result, with its cycle diagnostics, and no delay or pause is edited.

Rounds is separate from the planner's iteration count. Planner convergence is Schedule.Converged.

Methods#

DeepClone#

public LevelingResult DeepClone()

Returns a new LevelingResult with the same Rounds. Schedule isn't copied: the new instance points to the same ScheduleResult. To get an independent schedule, call result.Schedule.DeepClone().

Equals#

public bool Equals(LevelingResult? other)

Value equality: Schedule is compared with ScheduleResult.Equals (lists element by element) and Rounds with ==. GetHashCode follows the same fields.

Example#

using Plen;

// Monday, August 10, 2026: two tasks book the same developer full time.
var monday = Moment.FromYmdHm(2026, 8, 10, 8, 0) ?? throw new InvalidOperationException("invalid date");
TaskData Task(string id) => new(id) { StartDate = monday, Duration = 2.0 };
AssignmentData Assign(string task) => new() { Task = task, Resource = "dev", Value = 1.0 };

var data = new ProjectData
{
    Tasks = [Task("a"), Task("b")],
    Resources = [new ResourceData { Id = "dev" }],
    Assignments = [Assign("a"), Assign("b")],
};

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

var result = project.Level(new LevelingOptions());
Console.WriteLine($"rounds: {result.Rounds}");
foreach (var update in result.Schedule.Updates)
    Console.WriteLine($"{update.Id}: start {update.StartDate}, delay {update.LevelingDelay}");