Some constraint programming solvers and constraint modelling languages feature the Sort(L, P , S ) constraint, which holds if S is a nondecreasing rearrangement of the list L, the permutation being made explicit by the optional list P . However, such sortedness constraints do not seem to be used much in practice. We argue that reasons for this neglect are that it is impossible to require the underlying sort to be stable, so that Sort cannot be guaranteed to be a total-function constraint, and that L cannot contain tuples of variables, some of which form the key for the sort. To overcome these limitations, we introduce the StableKeysort constraint, decompose it using existing constraints, and propose a propagator. This new constraint enables a powerful modelling idiom, which we illustrate by elegant and scalable models of two problems that are otherwise hard to encode as constraint programs.
MotivationIn order to motivate our work, we consider the following human resource planning problem, which will serve as running example throughout this paper. Consider n tasks that are to be assigned to a given set of m employees. For each task i ∈ 1..n, let attribute A i denote the initially unknown employee performing it, B i its fixed beginning time, D i its fixed duration, and E i its fixed end time, with E i = B i + D i for all i ∈ 1..n. A first constraint is that tasks assigned to the same employee should not overlap in time. A second constraint deals with the allocation of breaks to each employee. This is done by stating a Shift constraint, which we now describe. A shift is a maximum sequence of tasks assigned to a same employee such that the time gap between any two consecutive tasks is shorter than a given threshold minBreak : that is, consecutive shifts of an employee are separated by a break of minimum duration minBreak , and consecutive tasks of a shift are separated by a gap shorter than minBreak . The span of a shift is the difference between the end time of its last task and the beginning time of its first task: see Figure 1. The Shift constraint holds if and only if the span of each shift of each employee is at most a given threshold maxSpan.