Candidate#

One alternative edit to score: an id and the SchedulingChanges to try. Create it with new Candidate() and the fluent setters, and pass a list of candidates to Project#evaluate or Project#evaluateWith.

Declaration#

package org.dhtmlx.plen;

public class Candidate extends ValueRecord implements DeepCloneable<Candidate>

Constructors#

Candidate()#

public Candidate()

Creates a candidate with id and changes set to null. Set both before passing it to evaluate.

Fields#

Field Type Default Description
id Id null Label for the candidate. Copied unchanged into CandidateResult.id. Uniqueness isn't checked.
changes SchedulingChanges null Edits to apply to the copy before scheduling it. Required: evaluate throws NullPointerException when it's null. An empty new SchedulingChanges() scores the plan as it is.

For how a stale changes.baselineId or a rejected operation in changes is reported, see Project#evaluate and CandidateResult.error.

Methods#

withId, withChanges#

public Candidate withId(Id value)
public Candidate withChanges(SchedulingChanges value)

Each setter assigns its field and returns this instance.

Returns: this Candidate.

deepClone#

public Candidate deepClone()

Returns a new candidate with the same id and a deep copy of changes. Nothing in the change set is shared with the original.

Returns: a new Candidate.

Errors: NullPointerException when changes is null.

copy#

public Candidate copy()

Returns a shallow copy: the new candidate holds the same id and changes objects.

Returns: a new Candidate.

equals, hashCode, toString#

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

Inherited from ValueRecord. Two candidates are equal when id and changes are equal. toString() prints both fields, for logging.

Example#

Score two ways to staff task 1: assign dev1 or assign dev2.

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

public class CandidateExample {
  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());
    for (CandidateResult candidate : result.candidates) {
      System.out.println(candidate.id + ": cost " + candidate.cost);
    }
  }
}