3

so basically my problem is, that OptaPlanner is throwing this:

java.lang.IllegalStateException: The entity (...) has a variable (previousEntry) with value (...) which has a sourceVariableName variable (nextEntry) with a value (...) which is not null.
Verify the consistency of your input problem for that sourceVariableName variable.
    at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.insert(SingletonInverseVariableListener.java:72)
    at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.afterVariableChanged(SingletonInverseVariableListener.java:51)
    at org.optaplanner.core.impl.domain.variable.listener.support.VariableListenerSupport.triggerVariableListenersInNotificationQueues(VariableListenerSupport.java:209)
    at org.optaplanner.core.impl.score.director.AbstractScoreDirector.triggerVariableListeners(AbstractScoreDirector.java:259)
    at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:36)
    at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:30)
    at org.optaplanner.core.impl.heuristic.move.CompositeMove.doMove(CompositeMove.java:108)
    at org.optaplanner.core.impl.heuristic.move.CompositeMove.doMove(CompositeMove.java:37)
    at org.optaplanner.core.impl.score.director.AbstractScoreDirector.doAndProcessMove(AbstractScoreDirector.java:187)
    at org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider.doMove(LocalSearchDecider.java:132)
    at org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider.decideNextStep(LocalSearchDecider.java:116)
    at org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:70)
    at org.optaplanner.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:88)
    at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:191)

I'm creating the move using this:

<cartesianProductMoveSelector>
    <ignoreEmptyChildIterators>true</ignoreEmptyChildIterators>
    <changeMoveSelector/>
    <swapMoveSelector/>
</cartesianProductMoveSelector>

I'm trying to optimize a chain, so I have a shadow variable (nextEntry) for my planning variable previousEntry. Everything is working if I use unionMoveSelector, but now I want to try to combine my moves so OptaPlanner can get out from a local optimum. I only have 1 planing variable.

EDIT: just updated to 7.19.0.Final the problem still exists...

EDIT2: just tested with FULL_ASSERT and got the same result, without cartesianProductMoveSelector I get a result:

Solving ended: time spent (371190), best score (0hard/-31648770soft), score calculation speed (81/sec), phase total (3), environment mode (FULL_ASSERT).

If I add cartesianProductMoveSelector I get exactly the same exception

EDIT3: well I just tested it with the vrp-example of optaplanner (7.17.0.Final) and got exact the same exception:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Solving failed.
at org.optaplanner.examples.common.swingui.SolverAndPersistenceFrame$SolveWorker.done(SolverAndPersistenceFrame.java:382)
at javax.swing.SwingWorker$5.run(SwingWorker.java:737)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:832)
at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:842)
at javax.swing.Timer.fireActionPerformed(Timer.java:313)
at javax.swing.Timer$DoPostEvent.run(Timer.java:245)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

Caused by: java.lang.IllegalStateException: The entity (Customer-7) has a variable (previousStandstill) with value (Customer-33) which has a sourceVariableName variable (nextCustomer) with a value (Customer-5) which is not null.
Verify the consistency of your input problem for that sourceVariableName variable.
at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.insert(SingletonInverseVariableListener.java:72)
at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.afterVariableChanged(SingletonInverseVariableListener.java:51)
at org.optaplanner.core.impl.domain.variable.listener.support.VariableListenerSupport.triggerVariableListenersInNotificationQueues(VariableListenerSupport.java:209)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.triggerVariableListeners(AbstractScoreDirector.java:261)
at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:36)
at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:30)
at org.optaplanner.core.impl.heuristic.move.CompositeMove.doMove(CompositeMove.java:108)
at org.optaplanner.core.impl.heuristic.move.CompositeMove.doMove(CompositeMove.java:37)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.doAndProcessMove(AbstractScoreDirector.java:189)
at org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider.doMove(LocalSearchDecider.java:132)
at org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider.decideNextStep(LocalSearchDecider.java:116)
at org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:70)
at org.optaplanner.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:88)
at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:191)
at org.optaplanner.examples.common.business.SolutionBusiness.solve(SolutionBusiness.java:329)
at org.optaplanner.examples.common.swingui.SolverAndPersistenceFrame$SolveWorker.doInBackground(SolverAndPersistenceFrame.java:370)
at javax.swing.SwingWorker$1.call(SwingWorker.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at javax.swing.SwingWorker.run(SwingWorker.java:334)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

I'll submit an issue

EDIT4: submitted issue can be found here

JohnnyAW
  • 2,866
  • 1
  • 16
  • 27
  • Turn on environmentMode FULL_ASSERT. Does it fail earlier, before the `doMove()` method there in that stacktrace? I suspect it will because I suspect your problem input might be corrupted (violation of the InverseRelationshipShadowVariable). – Geoffrey De Smet Mar 26 '19 at 18:54
  • I tested my implementation with `FULL_ASSERT` and got the same results. Check my edit for more info – JohnnyAW Mar 27 '19 at 08:20
  • My Class hierarchy has about 10-15 Classes and Interfaces but I only added 2 `entityClass` to my configuration. But I only have 1 `planningVariable` – JohnnyAW Mar 27 '19 at 08:37
  • Hmm, this *might* be a bug - when using CartesianProductMove together with a chained variable and an InverseRelationShadowVariable. Try reproducing it on the vehicle routing problem example in optaplanner-examples. If it reproduces there, [submit an issue in our issue tracker](https://issues.jboss.org/projects/PLANNER/summary) please. – Geoffrey De Smet Mar 27 '19 at 09:09
  • 1
    got the same exception on the example project, I'll submit an issue – JohnnyAW Mar 27 '19 at 09:34
  • Thank you. If you could add a link here too, that would be great. – Geoffrey De Smet Mar 28 '19 at 11:31
  • @GeoffreyDeSmet do you have any progress on that issue so far? Do you have it on your roadmap? We really need possibility to create composite moves, since we are trying to implement pickup/delivery - vrp. Is it possible for me to try to fix the bug and commit it to your repository? – JohnnyAW Sep 30 '19 at 10:22
  • 1
    It's in the backlog and not easy to fix, so it's competing with customer support tickets and new features for attention. I haven't seen other community users run into it yet. – Geoffrey De Smet Oct 01 '19 at 06:46

2 Answers2

3

experienced the same when creating a CompositeMove with multiple ChainedChange and ChainedSwapMoves. The reason for this is, that your first move might Change the PlanningValue of a PlanningEntity manipulated in a Move following that first one. While the creation of the moves already captures the Status of all the variables and values, the second move anticipates a not longer existing planning Status.

Example: chain before your Move:

(I) A -> B -> C -> D

your Composite Move: 1) ChainedChangeMove for Moving B in front of A 2) ChainedChangeMove for Moving D in front of C

in the move creation the values will be stored a shown in (I) in the moves. Move 1 will execute correct.

Solution after move 1): (II) B -> A -> C -> D

the second move will now try to move D behind B, but B is already referenced in the previousStandstill variable of A

You can create similiar scenarios with other versions of composite moves. As long as the chained moves save the status of the chain at creation of the move, union moves and compsite moves will potentially fail.

  • I am getting the same exception. If your analysis is correct, this might be avoidable with a selectionFilter that detects this situation and filters the move. Have you tried this or are there any other workarounds? – Ferdinand Wörister Apr 22 '20 at 14:10
  • Yes, the analysis is correct, and it can be avoided with a filter, see my answer. – Ferdinand Wörister Apr 22 '20 at 15:20
0

I have the same problem and managed to avoid the issue with a MoveFilter that prevents the situation Frank explains in his answer (one move affecting another in a compositMove). Here is my badly coded proof of concept for the workaround:

public class ParallelTaskMoveFilter
            implements SelectionFilter<EngineerRoutingSolution, CompositeMove<EngineerRoutingSolution>> {

        @Override
        public boolean accept(ScoreDirector<EngineerRoutingSolution> scoreDirector,
                CompositeMove<EngineerRoutingSolution> selection) {
            Move<EngineerRoutingSolution>[] childMoves = selection.getMoves();
            ChangeMove<EngineerRoutingSolution> firstMove = (ChangeMove<EngineerRoutingSolution>) childMoves[0];
            ChangeMove<EngineerRoutingSolution> secondMove = (ChangeMove<EngineerRoutingSolution>) childMoves[1];

            DailyRoute srcRoute1 = ((RouteItem) firstMove.getEntity()).getDailyRoute();
            DailyRoute destRoute1 = ((RouteItem) firstMove.getToPlanningValue()).getDailyRoute();
            DailyRoute srcRoute2 = ((RouteItem) secondMove.getEntity()).getDailyRoute();
            DailyRoute destRoute2 = ((RouteItem) secondMove.getToPlanningValue()).getDailyRoute();

            return !srcRoute1.equals(srcRoute2) && !srcRoute1.equals(destRoute2) && !destRoute2.equals(destRoute1)
                    && !srcRoute2.equals(destRoute1);
        }

    }