Search code examples
droolsoptaplanner

Score corruption when using computed values to calculate score


I have a use case where:

  1. A job can be of many types, says A, B and C.
  2. A tool can be configured to be a type: A, B and C
  3. A job can be assigned to a tool. The end time of the job depends on the current configured type of the tool. If the tool's current configured type is different from the type of the job, then time needs to be added to change the current tool configuration.

My @PlanningEntity is Allocation, with startTime and tool as @PlanningVariable. I tried to add the currentConfiguredToolType in the Allocation as the @CustomShadowVariable and update the toolType in the shadowListener's afterVariableChanged() method, so that I have the correct toolType for the next job assigned to the tool. However, it is giving me inconsistent results.

[EDIT]: I did some debugging to see if the toolType is set correctly. I found that the toolType is being set correctly in afterVariableChanged() method. However, when I looked at the next job assigned to the tool, I see that the toolType has not changed. Is it because of multiple threads executing this flow? One thread changing the toolType of the tool the first time and then a second thread simultaneously assigning the times the second time without taking into account the changes done by the first thread.

[EDIT]: I was using 6.3.0 Final earlier (till yesterday). I switched to 6.5.0 Final today. There too I am seeing similar results, where the toolType seems to be set properly in afterVariableChanged() method, but is not taken into account for the next allocation on that tool.

[EDIT]: Domain code looks something like below:

@PlanningEntity
public class Allocation {

private Job job;

// planning variables
private LocalDateTime startTime;
private Tool tool;

 //shadow variable
 private ToolType toolType;

 private LocalDateTime endTime;

 @PlanningVariable(valueRangeProviderRefs = TOOL_RANGE)
 public Tool getTool() {
    return  this.tool;
 }

 @PlanningVariable(valueRangeProviderRefs = START_TIME_RANGE)
 public LocalDateTime getStartTime() {
    return this.startTime;
 }

 @CustomShadowVariable(variableListenerClass = ToolTypeVariableListener.class,
        sources = {@CustomShadowVariable.Source(variableName = "tool")})
 public ToolType getCurrentToolType() {
   return this.toolType;
 }

 private void setToolType(ToolType type) {
    this.toolType = type;
    this.tool.setToolType(type);
 } 

 private setStartTime(LocalDateTime startTime) {
    this.startTime = startTime;
    this.endTime = getTimeTakenForJob() + getTypeChangeTime();
    ...
 }

 private LocalDateTime getTypeChangeTime() {
 //typeChangeTimeMap is available and is populated with data
    return typeChangeTimeMap.get(tool.getType);
 }

}

public class Tool {
 ...
private ToolType toolType;
getter and setter for this.

public void setToolType() { ...}

public ToolType getToolType() { ...}

}


public class ToolTypeVariableListener implements VariableListener<Allocation> {
...
@Override
public void afterVariableChanged(ScoreDirector scoreDirector, Allocation entity) {
  scoreDirector.afterVariableChanged(entity, "currentToolType");
  if (entity.getTool() != null && entity.getStartTime() != null) {
     entity.setCurrentToolType(entity.getJob().getType());
  }
  scoreDirector.afterVariableChanged(entity, "currentToolType");
}

[EDIT]: When I did some debugging, looks like the toolType set in the machine for one allocation is used in calculating the type change time for a allocation belonging to a different evaluation set. Not sure how to avoid this.

If this is indeed the case, what is a good way to model problems like this where the state of a item affects the time taken? Or am I totally off. I guess i am totally lost here.

[EDIT]: This is not an issue with how Optaplanner is invoked, but score corruption, when the rule to penalize it based on endTime is added. More details in comments.

[EDIT]: I commented out the rules specified in rules one-by-one and saw that the score corruption occurs only when the score computed depends on the computed values: endTime and toolTypeChange. It is fine when the score depends on the startTime, which is a planningVariable alone. However, that does not give me the best results. It gives me a solution which has a negative hard score, which means it violated the rule of not assigning the same tool during the same time to different jobs. Can computed values not be used for score calculations?

Any help or pointer is greatly appreciated.

best,

Alice


Solution

  • The ToolTypeVariableListener seems to lack class to the before/after methods, which can cause score corruption. Turn on FULL_ASSERT to verify.