0

I'm using solverManager to continually save the best score:

solverManager.solveAndListen(
            SINGLETON_TIME_TABLE_ID,
            this::findById,
            this::save
        )

My save() method just updates a global reference to the best solution and nothing else happens to it.

However, when I go to retrieve the best solution and get the score details, it does not always get the best solution:

val solution: MySolution = findById(SINGLETON_TIME_TABLE_ID)

println(solution.score) // prints 1100

scoreManager.updateScore(solution) // Sets the score

println(solution.score) // prints 1020 (it's now worse than before)

Simply calling scoreManager.updateScore(solution) seems to bring back a worse solution. In the above example, the score might go from 1100 down to 1020. Is there an obvious explanation for this?

I'm using SimpleScore and this happens well after all planning variables are assigned.

I'm using a variable listener ArrivalTimeUpdatingVariableListener : VariableListener.

Not sure what else is relevant. Thanks

DFx
  • 249
  • 3
  • 14

1 Answers1

2

This has all warning signs of a score corruption. Please run your solver for a couple minutes with <environmentMode>FULL_ASSERT</environmentMode>. If you'll see exceptions being thrown, you know that your constraints have a bug in them. What that bug is, that is impossible for me to know unless I see those constraints.

Lukáš Petrovický
  • 3,945
  • 1
  • 11
  • 20
  • Thank you! That was exactly the issue. – DFx Dec 16 '21 at 13:13
  • What was causing the score corruption? – Geoffrey De Smet Dec 16 '21 at 13:36
  • One constraint calculates unloading costs and corrupts it somehow. Visits can be to jobs or unloads. Jobs fill up the vehicle. Unloads take it away, but then an expense is calculated based on how much was taken away and the cost to unload at each specific location. I'm doing something in that calculation it doesn't like. – DFx Dec 16 '21 at 16:09
  • Just to add: the real problem came down to the constraintFactory not selecting all the PlanningVisits. I was just selecting the PlanningVehicles and since the unloading costs include using all the visits, there must have been scenarios where it wasn't incrementally adjusting it every time. Ie. OptaPlanner needs to be aware that shifting visits around and not just vehicles has an effect on the score in this case. – DFx Dec 16 '21 at 17:16
  • I think that this is a misunderstanding. OptaPlanner will only recalculate constraints for changes to facts which come from `forEach(...)`, `join(...)` etc. If you, for example, do a `visit.getVehicle().getCapacity()` and then subsequently change vehicle capacity, the constaint will not refresh unless it was actually started with `Vehicle` in the methods mentioned above. This is by design and can not be avoided. In that case, we do not know you are using `Vehicle`, you only told us you are using `Visit`. – Lukáš Petrovický Dec 16 '21 at 20:17
  • That makes sense. I used a ```join()``` to solve the problem. Thanks again for pointing me in the right direction. – DFx Dec 16 '21 at 21:01