Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The same code get different exception betwee environmentMode TRACKED_FULL_ASSERT and FULL_ASSERT #478

Closed
kentbill opened this issue Dec 8, 2023 · 2 comments · Fixed by #484
Assignees
Labels
bug Something isn't working regression A bug that was caused by another commit; usually indicates lack of test coverage.
Milestone

Comments

@kentbill
Copy link

kentbill commented Dec 8, 2023

Describe the bug
I have a project that uses the Chained Through Time pattern, when I debug it, an exception through from Timefold. But what makes me feel strange is that when I set different environmentMode values(TRACKED_FULL_ASSERT and FULL_ASSERT ), the different exception throws. So I don't know which is the actual exception.

Expected behavior
I expect FULL_ ASSERT and TRACKED_FULL_ASSERT will result in the same exception.

Actual behavior
environmentMode with FULL_ ASSERT and TRACKED_FULL_ASSERT resulted in different exceptions.

To Reproduce
When I set the environmentMode with FULL_ASSERT(SolverConfig.withEnvironmentMode(EnvironmentMode.FULL_ASSERT), or FAST_ASSERT, the exception is below.

java.lang.IllegalStateException: UndoMove corruption ([0/0/0/-22560/0/0/0/0/0/0]soft): the beforeMoveScore ([0/0/0/0]hard/[0/0/0/-775620/0/-8/-360/0/0/-3321]soft) is not the undoScore ([0/0/0/0]hard/[0/0/0/-798180/0/-8/-360/0/0/-3321]soft) which is the uncorruptedScore ([0/0/0/0]hard/[0/0/0/-798180/0/-8/-360/0/0/-3321]soft) of the workingSolution.

1) Enable EnvironmentMode TRACKED_FULL_ASSERT
(if you haven't already) to fail-faster in case there's a score corruption or variable listener corruption.
2) Check the Move.createUndoMove(...) method of the moveClass (ChainedSwapMove).
The move (PD04 {PD02} <-> PD02 {RES(D4-002)}) might have a corrupted undoMove (PD02 {RES(D4-002)} <-> PD04 {PD02}).
3) Check your custom VariableListeners (if you have any)
for shadow variables that are used by score constraints that could cause
the scoreDifference ([0/0/0/-22560/0/0/0/0/0/0]soft).

	at ai.timefold.solver.core.impl.score.director.AbstractScoreDirector.assertExpectedUndoMoveScore(AbstractScoreDirector.java:735)
	at ai.timefold.solver.core.impl.localsearch.decider.LocalSearchDecider.doMove(LocalSearchDecider.java:123)
	at ai.timefold.solver.core.impl.localsearch.decider.LocalSearchDecider.decideNextStep(LocalSearchDecider.java:97)
	at ai.timefold.solver.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:72)
	at ai.timefold.solver.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:82)
	at ai.timefold.solver.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:193)
	at ai.timefold.solver.core.impl.solver.DefaultSolverJob.call(DefaultSolverJob.java:110)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)

When I changed the environmentMode to TRACKED_FULL_ASSERT or NON_REPRODUCIBLE, then exception messages were below.

java.lang.IllegalStateException: The entity (PD01) has a variable (previousTaskOrResource) with value (PD03) which has a sourceVariableName variable (nextTask) with a value (null) which is not that entity.
Verify the consistency of your input problem for that sourceVariableName variable.
	at ai.timefold.solver.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.retract(SingletonInverseVariableListener.java:76)
	at ai.timefold.solver.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.beforeVariableChanged(SingletonInverseVariableListener.java:32)
	at ai.timefold.solver.core.impl.domain.variable.listener.support.VariableChangedNotification.triggerBefore(VariableChangedNotification.java:15)
	at ai.timefold.solver.core.impl.domain.variable.listener.support.VariableChangedNotification.triggerBefore(VariableChangedNotification.java:6)
	at ai.timefold.solver.core.impl.domain.variable.listener.support.AbstractNotifiable.triggerBefore(AbstractNotifiable.java:70)
	at ai.timefold.solver.core.impl.domain.variable.listener.support.VariableListenerNotifiable.notifyBefore(VariableListenerNotifiable.java:26)
	at ai.timefold.solver.core.impl.domain.variable.listener.support.VariableListenerSupport.beforeVariableChanged(VariableListenerSupport.java:161)
	at ai.timefold.solver.core.impl.domain.variable.listener.support.VariableListenerSupport.simulateGenuineVariableChange(VariableListenerSupport.java:262)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor.lambda$visitAllEntities$8(SolutionDescriptor.java:910)
	at ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor.visitAllEntities(SolutionDescriptor.java:924)
	at ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor.visitAllEntities(SolutionDescriptor.java:910)
	at ai.timefold.solver.core.impl.domain.variable.listener.support.VariableListenerSupport.forceTriggerAllVariableListeners(VariableListenerSupport.java:235)
	at ai.timefold.solver.core.impl.domain.variable.listener.support.VariableListenerSupport.recalculateAllShadowVariablesFromScratch(VariableListenerSupport.java:245)
	at ai.timefold.solver.core.impl.score.director.AbstractScoreDirector.assertExpectedUndoMoveScore(AbstractScoreDirector.java:699)
	at ai.timefold.solver.core.impl.localsearch.decider.LocalSearchDecider.doMove(LocalSearchDecider.java:123)
	at ai.timefold.solver.core.impl.localsearch.decider.LocalSearchDecider.decideNextStep(LocalSearchDecider.java:97)
	at ai.timefold.solver.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:72)
	at ai.timefold.solver.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:82)
	at ai.timefold.solver.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:193)
	at ai.timefold.solver.core.impl.solver.DefaultSolverJob.call(DefaultSolverJob.java:110)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)

Environment

Timefold Solver Version or Git ref: 1.5.0

Output of java -version: 17.0.5

Output of uname -a or ver:

Additional information

Provide any and all other information which might be relevant to the issue.

@kentbill kentbill added bug Something isn't working process/needs triage Requires initial assessment of validity, priority etc. labels Dec 8, 2023
Christopher-Chianelli added a commit to Christopher-Chianelli/timefold-solver that referenced this issue Dec 11, 2023
…h in TRACED_FULL_ASSERT TimefoldAI#478

Some variable listeners, such as CollectionInverseVariableListener,
expect their shadow not to be null. The same can also be true
for user's own variable listeners. Thus, we cannot set shadow variables
to null and can only simulate changes to geninue variables in order
to recalculate from scatch.
@triceo triceo removed the process/needs triage Requires initial assessment of validity, priority etc. label Dec 12, 2023
@triceo triceo added this to the v1.6.0 milestone Dec 12, 2023
@triceo
Copy link
Contributor

triceo commented Dec 12, 2023

Thanks for reporting, @kentbill !
The issue will be fixed in 1.6.0, to be released some time in January 2024.

@kentbill
Copy link
Author

Got it, thank you for your efforts!

triceo added a commit that referenced this issue Dec 12, 2023
…h in TRACED_FULL_ASSERT (#484)

Some variable listeners, such as CollectionInverseVariableListener,
expect their shadow not to be null. The same can also be true for user's
own variable listeners. Thus, we cannot set shadow variables to null and
can only simulate changes to geninue variables in order to recalculate
from scratch.

Fixes #478

---------

Co-authored-by: Lukáš Petrovický <[email protected]>
@triceo triceo added the regression A bug that was caused by another commit; usually indicates lack of test coverage. label Jan 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working regression A bug that was caused by another commit; usually indicates lack of test coverage.
Projects
None yet
3 participants