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

pvandenbrink pieter.van.den.brink at topicus.nl
Tue Jul 16 10:24:45 EDT 2013


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.
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...

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
  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.
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, and the
FamilyStart and FamilyEnd classes implement an equals and hashcode based on
the Family and Timeslot fields. 
(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
 
  






--
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.


More information about the rules-users mailing list