.. _case_assignment:
Case Assignment
-------------------
`DMCommunity's April 2025 challenge `_ revolves around case assignments in an analytical firm. It goes as follows:
.. admonition:: Case Assignments
An analytical firm assigns different cases to its analysts using the following rules:
* Case must be assigned to an analyst who has the same focus area as the case type
* Analysts can not work on a new case with an amount higher than their maximum allowed case amount.
* Analysts can not work on a new case if it puts them over their maximum total cases dollar amount
* Analyst Levels must correspond to Case Complexity: analysts can work only on new cases with complexity between their Minimum Case Complexity and Maximum Case Complexity (inclusive) as described in the following table:
.. raw:: html
| Qualification Level |
Minimum Case Complexity |
Maximum Case Complexity |
| 1 |
1 |
2 |
| 2 |
1 |
2 |
| 3 |
1 |
2 |
| 4 |
1 |
3 |
| 5 |
2 |
3 |
| 6 |
2 |
4 |
| 7 |
2 |
4 |
| 8 |
3 |
4 |
| 9 |
3 |
5 |
| 10 |
4 |
5 |
Together with this specification, we are given information on 8 analysts and 4 cases (see the original challenge).
For fun, we will be describing how to solve this challenge by using as little tables as possible.
In this way, this page will be a good example of some of the more advanced cDMN.
First, we work out our glossary, which describes all the symbols that will be used in our model.
As always, we begin by adding types, which represent specific value domains.
For brevity's sake, we have shortened the analyst's names to their initials.
.. raw:: html
| Type |
| Analyst |
String |
TS, SR, SH, JR, DS, DB, KJ, RH |
| Area |
String |
Technology, Research, Construnction |
| Case |
Int |
112, 113, 114, 115 |
| Level |
Int |
1..10 |
Next, we introduce a function for every analyst and case attribute, such as level, amount, complexity, etc.
Additionally, we add a function to map each level on the appropriate min and max complexity.
As a reminder, a function is a symbol that maps one type on another. For example, the function "level of Analyst" below will maps each analyst on their level.
.. raw:: html
| Function |
| level of Analyst |
Level |
| current amount for Analyst |
Int |
| caseload for Analyst |
Int |
| max case amount for Analyst |
Int |
| max total amount for Analyst |
Int |
| total amount assigned to Analyst |
Int |
| Case amount |
Int |
| Case complexity |
Int |
| Case type |
Int |
| Case assigned to analyst |
Analyst |
| min complexity of Level |
Int |
| max complexity of Level |
Int |
To model the focus areas of the analysts, we introduce a relation between Analyst and Area.
.. raw:: html
| Relation |
| Analyst focuses on Area |
Lastly, we finish our glossary by introducing a constant *overqualification*, which we will use to calculate the total overqualification.
.. raw:: html
| Constant |
| qualification |
Int |
With our glossary finished, we can start adding the analyst and case data in the form of data tables (see :ref:`datatable`).
Note that, if you are working in spreadsheet software, you can place these datatables in a separate tab to ensure a clean overview.
.. raw:: html
| Analyst info |
|
| D |
Analyst |
level of Analyst |
current amount for Analyst |
caseload for Analyst |
max case amount for Analyst |
max total amount for Analyst |
| 1 |
TS |
10 |
35000000 |
12 |
50000000 |
75000000 |
| 2 |
SR |
50 |
5000000 |
10 |
1000000 |
7000000 |
| ... |
... |
... |
... |
... |
... |
... |
.. raw:: html
| Focus areas |
|
| D |
Analyst |
Area |
Analyst focuses on Area |
| 1 |
TS |
Technology, Research, Construction |
Yes |
| 2 |
SR |
Technology, Research, Construction |
Yes |
| ... |
... |
... |
... |
.. raw:: html
| Case info |
|
| D |
Case |
Case amount |
Case complexity |
Case type |
| 1 |
112 |
50000 |
3 |
Technology |
| 2 |
113 |
200000 |
1 |
Technology |
| 3 |
114 |
1500000 |
4 |
Construction |
| 4 |
115 |
300000 |
4 |
Research |
.. raw:: html
| Level mapping |
|
| D |
Level |
min complexity for Level |
max complexity for Level |
| 1 |
1 |
1 |
2 |
| 2 |
2 |
1 |
2 |
| 3 |
... |
... |
... |
Now that these data tables model the *problem instance*, we can start modeling the actual *problem logic*.
What's more: we're going to model all problem logic in only three tables.
First, we introduce a constraint table to enforce all the case constraints w.r.t. analysts:
.. raw:: html
| Case <> Analyst constraints |
|
| E* |
Case |
Analyst |
Case assigned to analyst |
Analyst focuses on Case type |
max case amount for Analyst |
min complexity for level of Analyst |
max complexity for level of Analyst |
| 1 |
- |
- |
Analyst |
Yes |
>= Case amount |
<= Case complexity |
>= Case complexity |
Quite a big table! To better understand it, let's go over it step by step:
* The first two columns let us quantify over every case and every analyst (this can be read as "For every case and analyst, ...")
* Next, ``Case assigned to analyst = Analyst`` ensures we limit ourselves to only those combinations where the case is actually assigned to the analyst. Now, our reading becomes "For every case and analyst, if the case is assigned to the analyst, then ..."
* Each blue column is now a separate constraint, beginning with enforcing that the analyst has a focus on the case type, limiting the max case amount, etc.
* The last two columns are rather tricky: ``min complexity for level of Analyst`` actually *nests* two symbols: ``min complexity for Level`` and ``level of Analyst``. Since the latter is of type ``Level``, we are allowed to nest them into each other in this way. (Note: there's other ways to do this, but it's a nice example of advanced cDMN.)
Next, we add a constraint table to ensure that the analyst does not go over their max dollar case limit.
.. raw:: html
| Analyst may not exceed total |
|
| E* |
Analyst |
max total amount for Analyst |
| 1 |
- |
>= total amount assigned to Analyst + current amount for Analyst |
As our final decision table, we define the calculation for overqualification and the total assigned amount per analyst using a single count (``C+``) table:
.. raw:: html
| Overqualification and total amount |
|
| C+ |
Case |
Analyst |
Case assigned to analyst |
overqualification |
total amount assigned to Analyst |
| 1 |
- |
- |
Analyst |
level of Anayst - Case complexity |
Case amount |
That's all our problem logic done in just three tables.
Since we now want to minimize the overqualification, we finish by adding a Goal table as follows:
.. raw:: html
| Goal |
| Minimize overqualification |
And that's it!
We can now run the solver to find the optimal solution, in which the overqualification is twelve. Neat. :-)
.. code:: bash
Model 1
==========
Case_assigned_to_analyst := {112 -> SR, 113 -> KJ, 114 -> JR, 115 -> DS}.
total_amount_assigned_to_Analyst := {TS -> 0, SR -> 50000, SH -> 0, JR -> 1500000, DS -> 300000, DB -> 0, KJ -> 200000, RH -> 0}.
overqualification := 12.
You can also use the `online IDP-Z3 IDE `_ to play with the model yourself.
If you want to make your own case assignment, click on "Interactive Consultant" at the top, and click on the downwards arrow next to ``overqualification``.