Reputation: 860
I'm new to Optaplanner, and I try to solve a quite simple problem (for now, I will add more constraints eventually).
My model is the following: I have tasks (MarkerNesting
), that must run one at a time on a VirtualMachine
; the goal is to assign a list of MarkerNesting
s to VirtualMachine
s, having all machines used (we can consider that we have more tasks than machines as a first approximation). As a result, I expect each task to have a start and a end date (as shadow variables - not implemented yet).
I think I must use a chained variable, with the VirtualMachine
being the anchor (chained through time pattern) - am I right?
So I wrote a program inspired by some examples (tsp and coach and shuttle) with 4 machines and 4 tasks, and I expect each machine having one task when it is solved. When running it, though, I get some strange results : not all machines are used, but the worst is that I have duplicate MarkerNesting
instances (output example):
[VM 1/56861999]~~~>[Nesting(155/2143571436)/[Marker m4/60s]]~~~>[Nesting(816/767511741)/[Marker m2/300s]]~~~>[Nesting(816/418304857)/[Marker m2/300s]]~~~>[Nesting(980/1292472219)/[Marker m1/300s]]~~~>[Nesting(980/1926764753)/[Marker m1/300s]]
[VM 2/1376400422]~~~>[Nesting(155/1815546035)/[Marker m4/60s]]
[VM 3/1619356001]
[VM 4/802771878]~~~>[Nesting(111/548795052)/[Marker m3/180s]]
The instances are different (to read the log: [Nesting(id/hashcode)]
), but they have the same id, so they are the same entity in the end. If I understand well, Optaplanner clones the solution whenever it finds a best one, but I don't know why it mixes instances like that.
Is there anything wrong in my code? Is it a normal behavior?
Thank you in advance!
Upvotes: 1
Views: 307
Reputation: 860
As expected, I was doing something wrong: in Schedule
(the PlanningSolution
), I had a getter for a collection of VirtualMachine
, which calculate from another field (pools
: each Pool
holds VirtualMachine
s). As a result, there where no setter, and the solution cloner was probably not able to clone the solution properly (maybe because pools
is not annotated as a problem fact or a planning entity?).
To fix the problem, I removed the Pool
class (not really needed), leaving a collection of VirtualMachine
s in Schedule
.
To sum up, never introduce too many classes before you need them ^_^'
I pushed the correct version of my code on github.
Upvotes: 1
Reputation: 27312
Duplicate MarkerNesting instances that you didn't create, have the same content, but a different memory address, so are !=
from each other: that means something when wrong in the default solution cloner, which is based on reflection. It's been a while since anyone ran into an issue there. See docs section on "planning clone". The complex model of chained variables (which will be improved) doesn't help here at all.
Sometimes a well placed @DeepPlanningClone
fixes it, but in this case it might as well be due to the @InverseRelationShadowVariable
not being picked.
In any case, those system.out
's in the setter method are misleading - they can happen both by the solution cloner as well as by the moves, so without the solution hash (= memory address), they tell nothing. Try doing a similar system.out in either your best solution change events, or in the BestSolutionRecaller
call to cloneWorkingSolution()
, for both the original as well as the clone.
Upvotes: 1