Overload#

The resource overload of one evaluated stage. Each value comes paired with its difference from the baseline. It's the overload field of Metrics, so Project#evaluate returns one for the baseline and one for every stage of every candidate.

Overload is the sum over buckets of max(0, load โˆ’ capacity), in capacity ร— buckets. One unit is one bucket at 100 % over capacity. The bucket size is EvaluateOptions.level.basis when it's set. Otherwise it's derived from SchedulingConfig.durationUnit. The baseline and every stage of the call use the same basis.

Declaration#

package org.dhtmlx.plen;

public class Overload extends ValueRecord implements DeepCloneable<Overload>

Treat a returned Overload as read-only. Call deepClone() before changing it.

Constructors#

Overload()#

public Overload()

Creates an empty value: total is new Amount(0, 0), resources and focus are empty.

Fields#

Field Type Default Description
total Amount new Amount(0, 0) Overload of all resources together.
resources Vec<ResourceOverload> empty One entry per resource whose overload isn't 0 in this stage or in the baseline. Resources non-zero in the stage come first, in stage order, then resources non-zero only in the baseline.
focus Vec<FocusOverload> empty One entry per task in EvaluateOptions.focus, in that order. Empty when focus is empty.

Per resource, ResourceOverload.overload.value equals the sum of that resource's OverallocationWindow.overload values at the same basis.

Methods#

withTotal, withResources, withFocus#

public Overload withTotal(Amount value)
public Overload withResources(Vec<ResourceOverload> value)
public Overload withResources(Collection<? extends ResourceOverload> value)
public Overload withFocus(Vec<FocusOverload> value)
public Overload withFocus(Collection<? extends FocusOverload> value)

Each setter assigns its field and returns this instance. The Collection overloads copy the elements into a new Vec, and store null when given null.

Returns: this Overload.

deepClone#

public Overload deepClone()

Returns a deep copy. total, resources, focus and every nested list and Amount are copied.

Returns: a new Overload.

Errors: NullPointerException when resources or focus is null.

copy#

public Overload copy()

Returns a shallow copy that shares resources and focus with the original. total gets its own Amount instance.

Returns: a new Overload.

equals, hashCode, toString#

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

Inherited from ValueRecord. Two values are equal when every field is equal: nested objects and lists compare element by element, double values with Double.equals, so 0.0 and -0.0 aren't equal. toString() prints every field, for logging.

ResourceOverload#

The overload of one resource.

public class ResourceOverload extends ValueRecord implements DeepCloneable<ResourceOverload>
Field Type Default Description
resource Id null The resource. Never null in a returned value.
overload Amount new Amount(0, 0) Its overload. Inside FocusOverload, only the buckets that intersect the focus task count.

Setters: withResource(Id), withOverload(Amount). copy() gives the copy its own overload instance.

FocusOverload#

The overload inside one focus task's span.

public class FocusOverload extends ValueRecord implements DeepCloneable<FocusOverload>
Field Type Default Description
task Id null The focus task. Never null in a returned value.
resources Vec<ResourceOverload> null Overload per resource over the buckets that intersect the task's [start, end) in this stage. Lists every resource that's non-zero there in the stage or in the baseline, in the same order as Overload.resources. null when the task isn't in this stage, for example when the candidate removed it.

A milestone with zero span covers no bucket, so its resources are all 0. In the scheduled stage, the values show the overload around the task. In the leveled stage, they show what leveling couldn't resolve there.

Setters: withTask(Id), withResources(Vec<ResourceOverload>) and withResources(Collection<? extends ResourceOverload>). deepClone() keeps a null resources as null.

ResourceOverload and FocusOverload have the same deepClone, copy, equals, hashCode and toString members as Overload.

Amount#

A value and its difference from the baseline value. It's also the type of Metrics.conflicts and Metrics.cycles.

public class Amount extends ValueRecord {
  public double value;
  public double delta;

  public Amount(double value, double delta)
  public Amount copy()
}
Field Type Description
value double The value in this stage.
delta double value minus the baseline value. Negative when the stage has less than the baseline. 0 in the baseline's own metrics.

Amount is a mutable class. Every type that holds an Amount gives each of its copies (copy() and deepClone()) a separate instance, so changing one copy's Amount doesn't change another's. equals compares value and delta with Double.equals. A computed value can be -0.0, so compare with == or <= 0 to test for no overload. toString() toString() prints both.

Example#

Two tasks overload dev1 on the same days. Score moving one of them to dev2, then read the overload in total, per resource and around task 2.

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

public class OverloadExample {
  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),
            new TaskData(Id.num(2)).withStartDate(monday).withDuration(2.0)))
        .withResources(List.of(
            new ResourceData().withId(Id.str("dev1")),
            new ResourceData().withId(Id.str("dev2"))))
        .withAssignments(List.of(
            new AssignmentData().withId(Id.str("a1")).withTask(Id.num(1))
                .withResource(Id.str("dev1")).withValue(1.0),
            new AssignmentData().withId(Id.str("a2")).withTask(Id.num(2))
                .withResource(Id.str("dev1")).withValue(1.0)));

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

    SchedulingChanges changes = new SchedulingChanges();
    changes.assignments.update.add(new AssignmentUpdate(Id.str("a2"))
        .withResource(Patch.of(Id.str("dev2"))));

    EvaluateResult result = project.evaluate(
        List.of(new Candidate().withId(Id.str("move")).withChanges(changes)),
        new EvaluateOptions().withFocus(List.of(Id.num(2))));

    System.out.println("baseline total: " + result.baseline.overload.total.value);

    Metrics scheduled = result.candidates.get(0).scheduled;
    if (scheduled != null) {
      Overload overload = scheduled.overload;
      System.out.println("candidate total: " + overload.total.value
          + " (delta " + overload.total.delta + ")");
      for (ResourceOverload r : overload.resources) {
        System.out.println("  " + r.resource + ": " + r.overload.value
            + " (delta " + r.overload.delta + ")");
      }
      for (FocusOverload f : overload.focus) {
        double around = f.resources == null ? 0.0
            : f.resources.stream().mapToDouble(r -> r.overload.value).sum();
        System.out.println("  around task " + f.task + ": " + around);
      }
    }
  }
}