How to set score recalculation after undoMove for some planning entities? - optaplanner

For some planning entities, even the planning variables are the same, the shadow variables (e.g., the end time of a procedure) can be different. By defaut, the score of a solution after undoMove will not be recalculated. However, the structure of the solution after undoMove will be different, compared to the structure before move, due to the duration of the procedure is random. This will result the UndoMove Corruption. For these planning entities with random durations, can I recalculated the score after the undoMove. Or how can I fix this problem?
Many thanks.

If your solution is different after an undo move, that is a score corruption. It must not happen. As far as I know, your problem does not have a solution - undo move must result in a solution that has the same score as before the move was made.
Undo moves are performed very often. The solver tries various random moves, and before it decides to apply one of them, it needs to revert all the others. Therefore it is not possible for your undo moves to alter the solution in any material way.
If you are using a custom move, cache the values you are replacing, and then in the undo move, restore the values to their exact original cached versions.

Related

How to solve the scheduling problem with random durations? (undomoves will result different scores)

"A shadow variable is in essence the result of a formula/algo based on at least 1 planning variable (and maybe some problem properties). The same planning variables state should always deliver the exact same shadow variable state." However, for project scheduling problems with random durations, even the start time of a job remains the same as before move or undomove, the end time of the job will be different, because the duration is a random variable. Both the start time and the end time of a job are shadow variables. Then the score after undomove and beforemove will be different. How to deal with this situation?
When you say:
Then the score after undomove and beforemove will be different.
That is the root of your problem. Assume a solution X and a move M. Move M transforms solution X into solution Y. Undo move M2 must then transform solution Y back into solution X. (X and Y do not need to, and are not going to, be the same instance; they just need to represent the exact same state of the problem.)
Where you fall short is in modelling random duration of tasks. Every time the duration of a task changes, that is a change to the problem. When task duration changes, you are no longer solving the same problem - and you need to tell the solver that.
There are two ways of doing that:
Externally via ProblemChange. This will effectively restart the solver.
During a custom move, using ScoreDirector's before...() and after...() methods. But if you do that, then your undo moves must restore the solution back to its original state. They must reset the duration to what it was before.
There really is no way around this. Undo moves restore the solution to the exact same state as there was before the original move.
That said, I honestly do not understand how you implement randomness in your planning entities. If you share your code, maybe I will be able to give a more targetted answer.

How can I get the current move from the score director?

We are using the "auto delay until last" pattern from the docs, https://www.optaplanner.org/docs/optaplanner/latest/design-patterns/design-patterns.html
The loop detection computation is extremely expensive, and we would like to minimize the number of times it is called. Right now, it is being called in the #AfterVariableChanged method of the arrival time shadow variable listener.
The only information I have available in that method is the stop that got a new previous stop and the score director. A move may change several planning variables, so I will be doing the loop detection once for every planning variable that changed, when I should only have to do it once per move (and possibly undo move, unless I can be really clever and cache the loop detection result across moves).
Is there a way for me, from the score director, to figure out what move is being executed right now? I have no need to know exactly what move or what kind of move is being performed, only whether I am still in the same move as before.
I tried using scoreDirector.toString(), which has an incrementing number in it, but that number appears to be the same for a move and the corresponding undo move.
No, there is no access to a move from scoring code. That is by design - scoring needs to be independent of moves executed. Any solution has a score, and if two solutions represent the same state of the problem, their scores must equal - therefore the only thing that matters for the purposes of scoring is the state of the solution, not the state of the solver or any other external factor.

Optaplanner - soft scoring rule not working as expected

I built an application which implements a similar function as task assignment. I thought it works well until recently I noticed the solutions are not optimal. In details, there is a score table for each possible pair between machines and tasks, and usually the number of machines is much less than the number of tasks. I used hard/medium/soft rules, where the soft rule is incremental based on the score of each assignment from the score table.
However, when I reviewed the results after 1-2 hours run, I found out of the unassigned tasks there are many better choices (would achieve higher soft score if assigned) than current assignments. The benchmark reports indicate that the total soft score reached plateau within a hour and then stuck at that score level.
I checked the logic of rules - if the soft rule working perfectly, it should eventually find a way of allocation which achieves the highest overall soft score, whereas meeting the other hard/medium rules, isn't it?
I've been trying various things such as tuning algorithm parameters, scaling the score table, etc. but none delivers the optimal solution.
One problem is that you might be facing a score trap (see docs). In that case, make your constraint score more fine grained to deal with that.
If that's not the case, and you're stuck in a local optima, then I wouldn't play too much with the algorithm parameters - they will probably fix it, but you'll be overfitting on that dataset.
Instead, figure out the smallest possible move that gets you of that local optima and a step closer to the global optimum. Add that kind of moves as a custom move. For example if a normal swap move can't help, but you see a way of getting there by doing a 3-swap move, then implement that move.

MoveIteratorFactory purpose

As i can understand from the documentation the purpose of the "MoveIteratorFactory" is to generate the moves as they are needed to be played out at every step.
Is the "getSize" method how big the subset of moves will be?
What is the difference between "createOriginalMoveIterator" and "createRandomMoveIterator"?
Will the "createOriginalMoveIterator" regenerate a subset of moves again in a later step or not?
I guess that the move is played out after the method next() is called (after its creation) in both the cases?
Is this the best solution if there are a lot moves that need to be generated ,because in my case there are many moves that need to be first of all generated let alone played out?
Is there a smarter way to generate custom combined moves at every step that are based on the current state of the solution?
The MoveIteratorFactory is a more complex alternative to MoveListFactory which avoids creating a List<Move> by creating an Iterator<Move> instead. In Java 8 terms, it has a lot in common with a Stream.
Suppose you have 50k entities and 10k values. A list of all changemoves would contain 500m elements, causing memory issues and a serious delay loss every time a step starts. To avoid that, it generates a changemove just in time, at Iterator.next() or hasNext().
For that to work well, it needs to behave differently if the iterator needs to selects moves randomly (= might select the same move twice, this is not shuffled, it's random!) or original order.
Suppose you have 50k entities and 10k values. A list of all changemoves would contain 500m elements, causing memory issues and a serious delay loss every time a step starts. To avoid that, it generates a changemove just in time, at Iterator.next() or hasNext()

Is it possible not to recreate whole model every timer Tick in Elm?

For example, I need a timer on the page. So I can have an action every 100 ms
type Action = Tick Time
and I have field time in my Model. Model could be big, but I need to recreate it and whole view every 100 ms because of time field. I think it would not be effective performance-wise.
Is there another approach or I shouldn't worry about such thing?
The whole view isn't necessarily being recreated every time. Elm uses a Virtual DOM and does diffs to change only the bare minimum of the actual DOM. If large parts of your view are actually changing on every 100ms tick, then that could obviously cause problems, but I'm guessing you're only making smaller adjustments at every 100ms, and you probably have nothing to worry about. Take a look at your developer tools to see the whether the process utilization is spiking.
Your model isn't being recreated every 100ms either. There are optimizations around the underlying data structures (see this related conversation about foldp internals) that let you think in terms of immutability and pureness, but are optimized under the hood.