CandidateResult#
The score of one Candidate. Project.Evaluate and Project.EvaluateWith return one per candidate in EvaluateResult.Candidates, in input order.
Declaration#
namespace Plen;
public sealed class CandidateResult : IDeepCloneable<CandidateResult>, IEquatable<CandidateResult>
A result holds either an error or metrics, never both. Check Error first.
Properties#
| Property | Type | Description |
|---|---|---|
Id |
Id |
The candidate's Id, copied unchanged. required. |
Error |
RejectedOperation? |
Set when the candidate failed: the first rejected operation of its change set, or an input error from its solve or level run. Path is empty when the error has no input path. When set, Scheduled, Leveled and Cost are null. |
Scheduled |
Metrics? |
Metrics of the scheduled stage. Present on every candidate without Error. |
Leveled |
LeveledMetrics? |
Metrics of the leveled stage. Present only when EvaluateOptions.Level is set and the scheduled stage has no cycles. |
Cost |
double? |
The cost of the last stage present: Leveled.Metrics.Cost when Leveled is set, else Scheduled.Cost. Lower is better. null when Error is set. |
For how cost is computed, see Metrics.Cost.
Methods#
DeepClone#
public CandidateResult DeepClone()
Returns a deep copy. No list or nested object is shared with the original.
Equals#
public bool Equals(CandidateResult? other)
public override bool Equals(object? obj)
Value equality: compares Id, Error, Scheduled, Leveled and Cost field by field, with nested lists compared element by element. Cost compares with ==. GetHashCode is consistent with it.
ToString#
public override string ToString()
Returns a readable rendering of all properties, for logging.
Example#
Rank the scored candidates by cost and list the rejected ones separately.
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 = 2.0 }],
Resources = [new ResourceData { Id = "dev1" }, new ResourceData { Id = "dev2" }],
};
var project = new Project();
project.Solve(data, new SolveOptions());
var candidates = new List<Candidate>();
foreach (var dev in new[] { "dev1", "dev2" })
{
var changes = new SchedulingChanges();
changes.Assignments.Add.Add(new AssignmentData { Task = 1, Resource = dev, Value = 1.0 });
candidates.Add(new Candidate { Id = dev, Changes = changes });
}
// Rejected: "dev9" isn't in the project.
var bad = new SchedulingChanges();
bad.Resources.Remove.Add("dev9");
candidates.Add(new Candidate { Id = "drop-dev9", Changes = bad });
var result = project.Evaluate(candidates, new EvaluateOptions());
foreach (var c in result.Candidates.Where(c => c.Error is null).OrderBy(c => c.Cost))
Console.WriteLine($"{c.Id}: cost {c.Cost}, conflicts {c.Scheduled!.Conflicts.Value}");
foreach (var c in result.Candidates.Where(c => c.Error is not null))
Console.WriteLine($"{c.Id} rejected at {c.Error!.Path}: {c.Error.Message}");
Related#
Project.Evaluate- the call that scores the candidatesCandidate- the input this result scoresEvaluateResult- the call's result that holds oneCandidateResultper candidateMetrics- the stage metrics and howCostis computed- Evaluating alternatives - ranking candidates and handling failed ones