Domain modeling guide
Before writing any code, it helps to think through your domain model on paper. This guide walks you through the process of translating a real-world planning problem into a model that Timefold Solver can work with: identifying which parts of your domain change during planning, which relationships become planning variables, and how to structure entities to keep the search space manageable.
The structure of your model directly affects the size of the search space. Poor choices can make even small problems slow to solve.
|
This guide builds on concepts introduced in the Getting Started guides. If you haven’t completed one yet, |
-
Draw a class diagram of your domain model.
-
Make sure there are no duplications in your data model and that relationships between objects are clearly defined.
-
Create sample instances for each class. For example, in the employee rostering
Employeeclass, createAnn,Bert, andCarl.
-
-
Determine which relationships (or fields) change during planning and color them orange. One side of these relationships will become a planning variable later on. For example, in employee rostering, the
ShifttoEmployeerelationship changes during planning, so it is orange. However, other relationships, such as fromEmployeetoSkill, are immutable during planning.While reviewing your orange relationships, also check for the following:
-
Shadow variables: If an orange field can always be derived from other genuine planning variables without ambiguity, it is a shadow variable rather than a genuine planning variable. Color it purple instead. For example, the arrival time at a delivery stop can be calculated from the vehicle’s route and known travel times. See shadow variables for implementation details.
-
Ordered sequences: If the goal is to find an optimal order of elements rather than assigning each to a specific value, use the Chained Through Time pattern.
-
If any of those relationships involve time or date, see Assigning time to planning entities before continuing.
Only one side of a bi-directional relationship can be a genuine planning variable. The other side will become an inverse relation shadow variable later on. Keep bi-directional relationships orange.
-
-
If there is an orange many-to-many relationship, replace it with a one-to-many and a many-to-one relationship to a new intermediate class.
The following figure illustrates introducing a
ShiftAssignmentclass to represent the many-to-many relationship betweenShiftandEmployee.Shiftcontains every shift time that needs to be filled with an employee.
Timefold Solver does not currently support a
@PlanningVariableannotation on a collection. Planning list variable is not a means of achieving a many-to-one relationship; it serves to indicate that these values happen in a sequence one after another. -
Annotate a many-to-one relationship with a
@PlanningEntityannotation. Usually the many side of the relationship is the planning entity class that contains the planning variable. If the relationship is bi-directional, both sides are a planning entity class but usually the many side has the planning variable and the one side has the shadow variable. For example, in employee rostering, theShiftAssignmentclass has an@PlanningEntityannotation. -
Make sure each planning entity is meaningful without its planning variables. When all planning variables are
null, a business person should still be able to describe what the entity represents. A planning entity class cannot consist of only planning variables or an ID and only planning variables.-
Remove any surplus
@PlanningVariableannotations so that they become problem properties. Doing this significantly decreases the search space size and significantly increases solving efficiency. For example, in employee rostering, theShiftAssignmentclass should not annotate both theShiftandEmployeerelationship with@PlanningVariable. -
A surrogate ID alone does not count as a problem property. The entity needs at least one meaningful, identifying field beyond its ID and planning variables.
-
In some cases, multiple planning entity instances have the same set of problem properties. In such cases, add an extra problem property to distinguish them. For example, in employee rostering, the
ShiftAssignmentclass has the problem propertyShiftas well as the problem propertyindexInShiftto tell apart multiple assignments to the same shift.There is no need to add a hard constraint to ensure that two planning entities are different. Two entities which .equals(…) each other are strictly forbidden and fail fast.
-
-
Choose the model in which the number of planning entities is fixed during planning. If the count of planning entities can vary depending on the solution, the solver cannot establish a fixed search space to explore. This is a common first-timer mistake: modeling from the perspective of the resource rather than the work item.
For example, in employee rostering, it is impossible to know in advance how many shifts each employee will have before Timefold Solver solves the model and the results can differ for each solution found. On the other hand, the number of employees per shift is known in advance, so it is better to make the
Shiftrelationship a problem property and theEmployeerelationship a planning variable as shown in the following examples.
Once you have completed these steps, implement your model using the building blocks reference.