Originally posted by: Petr Vilím
Hello,
I tried your model using CP Optimizer versions 12.10, 12.9 and 12.8. What I wrote in the previous post is mostly for the default search type Restarts, from the file I see that you're using MultiPoint. So I tried both. I also set Workers=4 and TimeLimit 60s. Here are results:
Version 12.10 + Multipoint, first solution after 17.37s, final solution: 332431.5; 0; -35397885; 0; 0; 0; 0; 0; 0 (gap is 99.15% @ crit. 1 of 9)
Version 12.10 + Restart: first solution after 5.57s, final solution 662032.8; 0; -109595657; 0; 0; 0; 0; 0; 0 (gap is 100.0% @ crit. 3 of 9)
Version 12.9 + Multipoint: no solution found
Version 12.9 + Restart: first solution after 8.74s, final solution 662032.8; 0; -110547086; 0; 0; 0; 0; 0; 0 (gap is 100.0% @ crit. 3 of 9)
Version 12.8 + MultiPoint: no solution found
Version 12.8 + Restart: first solution after 33.5s, final solution 342980.; 0; -34138004; 0; 0; 0; 0; 0; 0 (gap is 93.02% @ crit. 1 of 9)
From those results, I guess that you're using version 12.9 or older. So my recommendation is to upgrade and do not change SearchType to MultiPoint (because Restart is the default).
I also noticed repeating pattern of constraints like the following one:
(0 == sizeOf("V_taskSlice#0")) => (0 == presenceOf("V_taskSlice#0"));
The constraint above is: if V_taskSlice#0 has size 0 then it should be absent. As a result, V_taskSlice#0 never has size 0 because in this case it simply doesn't exit (it is absent). In other words, this constraint can be replaced by:
sizeOf("V_taskSlice#0", 1) > 0;
Because if V_taskSlice#0 is absent then sizeOf returns the second parameter 1 and the constraint is true. And if V_taskSlice#0 is present then sizeOf returns it size and it must be bigger than 0.
Currently we don't have a presolve for this transformation, so if you do it manually then your model will propagate better and you may get better performance.
But there is one more repeating pattern, improving this one can help quite a lot:
span("V_task#0", ["V_taskSlice#0"]);
(presenceOf("V_task#0") >= 1) => (sum([sizeOf("V_taskSlice#0")]) == 4259);
The first constraint "span" says: There's only one slice for V_task#0. As the result the two interval variables are actually identical. They could be either both present or both absent. And if they are both present then they are synchronize.
The second constraint says that if V_task#0 is present then size of V_taskSlice#0 is 4259. However, considering that V_task#0 and V_taskSlice#0 are basically the same interval variables, it could be rewritten to:
sizeOf("V_taskSlice#0", 4259) == 4259;
Or:
sizeOf("V_task#0", 4259) == 4259;
Maybe in the future you will have more slices per task? Then you may keep the original constraints and add redundant constraint that will improve the propagation:
sizeOf("V_task#0", 4259) >= 4259;
BTW, if you plan to have more slices for a task then it is good to break symmetries in the solution by ordering them in time and by forcing only the first slices to be present:
endBeforeStart("task1slice1", "task1slice2");
presenceOf("task1slice1") >= presenceOf("task1slice2");
Best regards, Petr
#DecisionOptimization#OPLusingCPOptimizer