I am trying to implement a predecessor constraint similar to the Job Scheduling example given in java. But I struggle with the ordering constraint definition to consider predecessors. I have defined my time slots simply as ordered integers : @dataclass class Timeslot: slot : int And my operations as planning entities with few boolean operations and predecessors as a list of other operations id : @planning_entity @dataclass class Operation: id: Annotated[int, PlanningId] name: str predecessors: list[int] timeslot: Annotated[Timeslot, PlanningVariable] = field(default=None) def isPred(self,other): return other.id in self.predecessors def isAfter(self,other): return self.timeslot.slot < other.timeslot.slot And then my constraint as : def precondition_conflict(constraint_factory: ConstraintFactory) -> Constraint: # Respect order constraints return ( constraint_factory.for_each_unique_pair(Operation) .filter(lambda op1, op2 : op1.isPred(op2)) .filter(lambda op1, op2 : op1.isAfter(op2)) .penalize(HardSoftScore.ONE_HARD) .as_constraint("Order conflict") ) Then I instanciate my problem : operations.append(Operation(1,"OP N°1 : Bake the cake",[3])) operations.append(Operation(2,"OP N°2 : Enjoy your meal",[4])) operations.append(Operation(3,"OP N°3 : Mix flour, eggs and whatever they say in the recipe",[])) operations.append(Operation(4,"OP N°4 : take it out of the oven",[1])) But the solver keeps giving me solutions where the operations order is incorrect, with 0 hard constraint violated. For instance : INFO:timefold.solver:Solving ended: time spent (30056), best score (0hard/0soft), move evaluation speed (219895/sec), phase total (2), environment mode (PHASE_ASSERT), move thread count (NONE). INFO:app:+------------------+------------------+ INFO:app:|0 |OP N°4 : take it out of the oven| INFO:app:+------------------+------------------+ INFO:app:|1 |OP N°2 : Enjoy your meal| INFO:app:+------------------+------------------+ INFO:app:|2 |OP N°3 : Mix flour, eggs and whatever they say in the recipe| INFO:app:+------------------+------------------+ INFO:app:|3 |OP N°1 : Bake the cake| INFO:app:+------------------+------------------+ Where obviously I expected 3 -> 1 -> 4 -> 2 Where did I do it wrong? Continue reading...