在optaplanner中使用anchorshadowed变量的Variablelistener损坏

时间:2017-04-07 16:12:25

标签: java optaplanner

我正在尝试解决一个看起来像时间窗车辆路由问题的规划问题。

所以我正在寻找一个包含任务列表的解决方案。任务可以分配给两名工人中的一名。

我的Task类看起来像那样(我没有剪切/粘贴所有的getter和setter):

@PlanningEntity(difficultyComparatorClass = TaskDifficultyComparator.class)
public class Task implements Location {
    private String location;
    private LocalTime arrivalTime;
    private Location previousLocation;
    private Task nextTask;
    private StartLocal startLocal;


    private Duration taskDuration = Duration.ofMinutes(20);
    private LocalTime readyTime;
    private LocalTime dueTime;

    @PlanningVariable(valueRangeProviderRefs = {"tasks", "startLocal"},
            graphType = PlanningVariableGraphType.CHAINED)
    public Location getPreviousLocation() {
        return previousLocation;
    }
    public void setPreviousLocation(Location previousLocation) {
        this.previousLocation = previousLocation;
    }

    @Override
    public String {return location;}

    @Override
    public void setLocation(String location) {this.location = location;}

    public int getTimeToGoTo(Location location) {
        ....
    }

    @AnchorShadowVariable(sourceVariableName = "previousLocation")
    public StartLocal getStartLocal() {
        return startLocal;
    }
    public void setStartLocal(StartLocal startLocal) {
        this.startLocal = startLocal;
    }

    @CustomShadowVariable(variableListenerClass = ArrivalTimeVariableListener.class,
            sources = {@CustomShadowVariable.Source(variableName = "previousLocation")})
    public LocalTime getArrivalTime() {
        return arrivalTime;
    }
    public void setArrivalTime(LocalTime arrivalTime) {
        this.arrivalTime = arrivalTime;
    }
}

我的变量监听器类是:

public class ArrivalTimeVariableListener implements VariableListener<Task> {
    @Override
    public void beforeEntityAdded(ScoreDirector scoreDirector, Task task) {}

    @Override
    public void afterEntityAdded(ScoreDirector scoreDirector, Task task) {
        updateArrivalTime(scoreDirector, task);
    }

    @Override
    public void beforeVariableChanged(ScoreDirector scoreDirector, Task task) {        }

    @Override
    public void afterVariableChanged(ScoreDirector scoreDirector, Task task) {
        updateArrivalTime(scoreDirector, task);
    }

    @Override
    public void beforeEntityRemoved(ScoreDirector scoreDirector, Task task) {        }

    @Override
    public void afterEntityRemoved(ScoreDirector scoreDirector, Task task) {        }

    private void updateArrivalTime(ScoreDirector scoreDirector, Task task){
        LocalTime arrivalTimeInThisLocation = calculateArrivalTime(task);
        Task shadowTask = task;
        while (shadowTask != null) {
            scoreDirector.beforeVariableChanged(shadowTask, "arrivalTime");
            shadowTask.setArrivalTime(arrivalTimeInThisLocation);
            scoreDirector.afterVariableChanged(shadowTask, "arrivalTime");
            shadowTask = shadowTask.getNextTask();
            if(shadowTask!=null)arrivalTimeInThisLocation = calculateArrivalTime(shadowTask);
        }
    }

    @VisibleForTesting
    static public LocalTime calculateArrivalTime(Task task){
        LocalTime whenArriveAtPreviousLocation = task.getPreviousLocation().getArrivalTime();
        int secondsToGo = task.getTimeToGoTo(task.getPreviousLocation());
        long secondsToCompleteLastTask = 0;
        if(task.getPreviousLocation() instanceof Task){
            secondsToCompleteLastTask = ((Task) task.getPreviousLocation()).getTaskDuration().getSeconds();
        }
        LocalTime whenArriveInThisLocationASAP = whenArriveAtPreviousLocation.
                plusSeconds(secondsToCompleteLastTask).
                plusSeconds(secondsToGo);

        if(whenArriveInThisLocationASAP.isAfter(task.getReadyTime())){                
            return whenArriveInThisLocationASAP;
        }
        return task.getReadyTime();
    }
}

当我尝试解决我的问题时,我遇到以下错误:

VariableListener损坏:在触发所有VariableListener而不更改真实变量后,实体(Task s shadow variable(Task.arrivalTime)的损坏值(09:32)更改为未损坏的值(09:33) 。 可能该影子变量的VariableListener类(Task.arrivalTime)在completedAction(计算初始分数)之后其源之一发生更改时忘记更新它。

我知道此问题与NativeScript重复。 但我(非常非常)仔细阅读了这个SOF问题的答案,我无法理解我做错了什么。

我很清楚,变量监听器在我的用例中的作用是更新我们刚刚更改的任务之后的任务的“到达时间”。不是吗?

2 个答案:

答案 0 :(得分:0)

updateArrivaltime()添加到方法beforeValueChanged()

我的猜测是你在FULL_ASSERT

答案 1 :(得分:0)

好的,我发现了我做错了。

在我的问题中很难看出我做错了什么。问题是我将解决方案的shadows变量初始化为非null值。我的单元测试中有以下代码:

Task task1 = new Task();
task1.setPreviousTask(task0);
task0.setNextTask(task1);

//...
solution.computeAllArrivalTimes();

初始化阴影变量和规划变量不是一个好主意。如果我将它们设置为null,那么每件事都会像魅力一样。

我只需要在“calculateArrivalTime”中添加一些空值检查以允许调用此方法。