EvaluateResult#

Holds every candidate of one Project#evaluate or Project#evaluateWith call, each scored against the same baseline. Those calls are the only way to obtain one.

Declaration#

package org.dhtmlx.plen;

public class EvaluateResult extends ValueRecord implements DeepCloneable<EvaluateResult>

Fields#

Field Type Description
baselineId String Token of the accepted baseline the candidates were scored against.
baseline Metrics Metrics of the reference state. Every delta in it is 0.
candidates Vec<CandidateResult> One result per candidate, in input order.

baselineId#

public String baselineId = null;

The project's accepted baseline token at the time of the call. evaluate always sets it. When EvaluateOptions.clearFirst is true, it is still the accepted state's token. Set it as baselineId on the SchedulingChanges of the candidate you commit. Project#apply then rejects the commit if the project changed since the call.

baseline#

public Metrics baseline = null;

The reference that every candidate is compared with. This is the accepted state, or its cleared copy when clearFirst is true. Its deltas are 0 by definition. baseline.cost is the cost of the baseline itself. A candidate whose CandidateResult.cost is lower scores better than leaving the plan unchanged.

candidates#

public Vec<CandidateResult> candidates = new Vec<CandidateResult>();

One CandidateResult per input candidate, in the order of the candidates argument. Sequential and parallel execution keep the same order. A failed candidate stays in the list with error set and no metrics. A call-level error throws instead (see Project#evaluate).

Methods#

withBaselineId, withBaseline, withCandidates#

public EvaluateResult withBaselineId(String value)
public EvaluateResult withBaseline(Metrics value)
public EvaluateResult withCandidates(Vec<CandidateResult> value)
public EvaluateResult withCandidates(java.util.Collection<? extends CandidateResult> value)

Each setter assigns its field and returns this instance. The Collection overload copies the elements into a new Vec, and null sets the field to null.

Returns: this EvaluateResult.

deepClone#

public EvaluateResult deepClone()

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

Returns: a new EvaluateResult.

Errors: NullPointerException when baseline or candidates is null. A result returned by evaluate always has both set.

copy#

public EvaluateResult copy()

Returns a shallow copy. The new result holds the same baseline and candidates objects.

Returns: a new EvaluateResult.

equals, hashCode, toString#

public boolean equals(Object other)
public int hashCode()
public String toString()

Inherited from ValueRecord. Two results are equal when baselineId and baseline are equal and candidates match element by element. toString() prints all fields, for logging.

Example#

Score two ways to staff task 1, then commit the one with the lowest cost:

import java.util.ArrayList;
import java.util.List;
import org.dhtmlx.plen.*;

public class EvaluateResultExample {
  public static void main(String[] args) throws Exception {
    Moment monday = Moment.fromYmdHm(2026, 8, 10, 8, 0);
    ProjectData data = new ProjectData()
        .withTasks(List.of(
            new TaskData(Id.num(1)).withStartDate(monday).withDuration(2.0)))
        .withResources(List.of(
            new ResourceData().withId(Id.str("dev1")),
            new ResourceData().withId(Id.str("dev2"))));

    Project project = new Project();
    project.solve(data, new SolveOptions());

    List<Candidate> candidates = new ArrayList<>();
    for (String dev : List.of("dev1", "dev2")) {
      SchedulingChanges changes = new SchedulingChanges();
      changes.assignments.add.add(new AssignmentData()
          .withId(Id.str("a-" + dev))
          .withTask(Id.num(1))
          .withResource(Id.str(dev))
          .withValue(1.0));
      candidates.add(new Candidate().withId(Id.str(dev)).withChanges(changes));
    }

    EvaluateResult result = project.evaluate(candidates, new EvaluateOptions());
    System.out.println("baseline cost: " + result.baseline.cost);

    CandidateResult best = null;
    for (CandidateResult c : result.candidates) {
      if (c.error != null || c.cost == null) {
        continue;
      }
      if (best == null || c.cost < best.cost) {
        best = c;
      }
    }

    if (best != null) {
      Id bestId = best.id;
      SchedulingChanges chosen = candidates.stream()
          .filter(c -> c.id.equals(bestId))
          .findFirst()
          .orElseThrow()
          .changes;
      chosen.baselineId = result.baselineId;
      project.apply(chosen);
      project.solve(null, new SolveOptions());
    }
  }
}