Custom shadow variables ARE supported in optapy
: https://www.optapy.org/docs/latest/shadow-variable/shadow-variable.html#customVariableListener ; It uses the old style of @CustomShadowVariable
(@custom_shadow_variable
in Python) instead of @ShadowVariable
. However, ListVariableListener
is not currently supported. You can use the old chained model of the domain and constraints, which should be fully supported in optapy
. Support for the new @ShadowVariable
and ListVariableListener
will be added in a future version of optapy
.
Here how the variable listener would look in Python:
from optapy import variable_listener
@variable_listener
class StartTimeUpdatingVariableListener:
def beforeEntityAdded(self, scoreDirector, task):
pass
def afterEntityAdded(self, scoreDirector, task):
self.updateStartTime(scoreDirector, task)
def beforeVariableChanged(self, scoreDirector, task):
pass
def afterVariableChanged(self, scoreDirector, task):
self.updateStartTime(scoreDirector, task)
def beforeEntityRemoved(self, scoreDirector, task):
pass
def afterEntityRemoved(self, scoreDirector, task):
pass
def updateStartTime(self, scoreDirector, sourceTask):
previous = sourceTask.getPreviousTaskOrEmployee()
shadowTask = sourceTask
previousEndTime = None if previous is None else previous.getEndTime()
startTime = self.calculateStartTime(shadowTask, previousEndTime)
while shadowTask is not None and shadowTask.getStartTime() != startTime:
scoreDirector.beforeVariableChanged(shadowTask, "startTime")
shadowTask.setStartTime(startTime)
scoreDirector.afterVariableChanged(shadowTask, "startTime")
previousEndTime = shadowTask.getEndTime()
shadowTask = shadowTask.getNextTask()
startTime = self.calculateStartTime(shadowTask, previousEndTime)
def calculateStartTime(self, task, previousEndTime):
if task is None or previousEndTime is None:
return None
return max(task.getReadyTime(), previousEndTime)
and here how it can be used in a @custom_shadow_variable
:
from optapy import planning_entity, planning_variable, custom_shadow_variable, planning_variable_reference
@planning_entity
class Task:
# ...
@custom_shadow_variable(variable_listener_class = StartTimeUpdatingVariableListener,
sources=[planning_variable_reference('previousTaskOrEmployee')])
def get_start_time(self):
return self.start_time
def set_start_time(self, start_time):
self.start_time = start_time