[rules-users] OptaPlanner: score corruption when using insertLogical with custom objects

Geoffrey De Smet ge0ffrey.spam at gmail.com
Tue Jul 16 10:54:51 EDT 2013


On 16-07-13 16:24, pvandenbrink wrote:
> Hi,
>
> I've been using Drools Planner with success for a while for our Conversation
> planning tool. It's used by schools to plan conversations between teachers
> and parents of schoolgoing children.
Great to hear :)
Sounds like an interesting use case story.
> Recently I checked on the new developments on Drools (the current version
> we're using in production is 5.4.0.FINAL) and started to upgrade to
> OptaPlanner 6.0.0.Beta5.
> Everything looked fine, and seeing how it's now easier to check which
> constraints are broken in a given solution, I decided to have a look at that
> as well.
> And that's where I noticed that we actually had an issue with score
> corruption in one of our rules...
Do you have this issue in 5.4 too? E.g.: the 5.4 equivalent of full 
assert (TRACE) does not detect score corruption?
>
> The goal of the rule in case is to minimize the amount of timeslots between
> the first and last Conversation of a family (they can have conversations for
> multiple children.)
> The rule uses custom helper objects, like in the NurseRostering example,
> which are added with insertLogical.
> Conversation is the planning entity, which has the planning variable:
> timeslot. FamilyStart and FamilyEnd are custom helper objects to register
> the timeslot of the first and last conversation for a family.
>
> The relevant rules are as follows:
>
> rule "familyStart"
> 	salience 1
> 	when
> 		Conversation(
> 			family != null, $family: family,
> 			timeslot != null, $timeslot: timeslot);
> 		
> 		not Conversation(
> 			family == $family,
> 			timeslot < $timeslot);
> 	then		
> 		insertLogical(new FamilyStart($family, $timeslot));
> end
>
> rule "familyEnd"
> 	salience 1
> 	when
> 		Conversation(
> 			family != null, $family: family,
> 			timeslot != null, $timeslot: timeslot);
> 		
> 		not Conversation(
> 			family == $family,
> 			timeslot > $timeslot);
> 	then
> 		insertLogical(new FamilyEnd($family, $timeslot));
> end
>
> rule "familyCompact"
> 	when
> 		$start: FamilyStart(
> 			family != null, $family: family,
> 			timeslot != null, $timeslotBegin: timeslot);
> 		
> 		$end: FamilyEnd(
> 			family == $family,
> 			(timeslot.id - $timeslotBegin.id > family.minimumTimeslotsRequired),
> 			timeslot != null, $timeslotEnd: timeslot);
> 	then
> 		scoreHolder.addSoftConstraintMatch(kcontext, -(($timeslotEnd.getId() -
> $timeslotBegin.getId()) - $family.getMinimumTimeslotsRequired()));
> end
>
> When running one of my example schedules in FULL_ASSERT mode, the following
> error appears during the LocalSearch phase:
>
> Exception in thread "main" java.lang.IllegalStateException: Score
> corruption: the workingScore (-2hard/-119soft) is not the uncorruptedScore
> (-2hard/-118soft) after completedAction (Teacher 3 family 11 timeslot 2 =>
> 12):
>    The corrupted scoreDirector has 1 ConstraintMatch(s) which are in excess
> (and should not be there):
>      defaultpkg/familyCompact/level1/[FamilyEnd Family 11, Timeslot 12,
> FamilyStart Family 11, Timeslot 7]=-1
Maybe that "[FamilyEnd Family 11, Timeslot 12, FamilyStart Family 11, 
Timeslot 7]" exists twice?
Once way to find out is to put a debug breakpoint at the throw of the 
exception
and compare the ConstraintMatchTotal's ConstraintMatch's justificationList.
>    The corrupted scoreDirector has no ConstraintMatch(s) which are missing.
>    Check your score constraints.
>    
> I use a custom ChangeMove and SwapMove implementation. I've also tried using
> the new generic Moves, these have the same problem.
Interesting: that proves it's not a custom move problem.
> It seems like when a move happens that should update an inserted FamilyStart
> or FamilyEnd because of a change in timeslot, this change isn't properly
> reflected in the scoreDirector.
> Do you have any idea what could cause this corruption? The moves do call
> beforeVariableChanged and afterVariableChanged on the scoreDirector,
Your test above proves that's ok. Use generic moves for further tests 
first pls.
>   and the
> FamilyStart and FamilyEnd classes implement an equals and hashcode based on
> the Family and Timeslot fields.
1) But how do Family and Timeslot implement their equals/hashcode?
My first guess would be to start looking at this.

2) There's also the remote probability there's a bug in drools - in 
which case we'd want a reproducer attached on a jira so we can fix it.
> (Actually, I've also tried using the default equals and hashcode of Object
> for these 2 classes, which causes corruption much faster and with more
> ConstraintOccurrences.)
>
> Thanks for any insights,
>
> Pieter
>   
HTH :)
>    
>
>
>
>
>
>
> --
> View this message in context: http://drools.46999.n3.nabble.com/OptaPlanner-score-corruption-when-using-insertLogical-with-custom-objects-tp4024932.html
> Sent from the Drools: User forum mailing list archive at Nabble.com.
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-users
>



More information about the rules-users mailing list