[rules-users] null planning value - Was: Planner 5.3.Final - "presumedScore is corrupted" when using "update" on the rules working memory

Geoffrey De Smet ge0ffrey.spam at gmail.com
Wed Dec 7 10:49:05 EST 2011



Op 07-12-11 16:13, Patrik Dufresne schreef:
> During my debugging, I notice the call to getWorkingFacts() doesn't 
> include the planning entities. To make sure, I've run the NQueens 
> example (that use the same construction heuristic) : the call 
> to getWorkingFacts() include the planning entities.
>
> After more debugging, I figure out the problem. The ValueRange of my 
> PlanningEntity include 'null'. I use null for un-assigned shift. In 
> PlanningVariableDescriptor.java:149, the check for initialized 
> variable return False if the value is null. Then my planning entity is 
> wrongly identify as not initialized and the 
> SolutionDescriptor.java:135 doesn't include it in the facts list.
>
Null is currently not supported as a planning value (the entity gets 
seen as uninitialized). Please create an issue for that, you're not the 
only one running into it.
I want to fix this for 5.4, but it's more that it looks on the surface.
> So how do I fix it ?
Workaround it really :(
Create a planning value that represents null, but isn't. Teach your 
score rules to deal with that special value.
For example, if it's a Room, then give Room a property boolean 
unassigned and add 1 Room with that boolean unassigned = true (all 
others are false).
>
> 2011/12/7 Geoffrey De Smet <ge0ffrey.spam at gmail.com 
> <mailto:ge0ffrey.spam at gmail.com>>
>
>
>
>     Op 07-12-11 02:18, Patrik Dufresne schreef:
>>     I'm still experimenting with Drools Planner and I also have the
>>     exact same issue :
>>
>>         java.lang.IllegalStateException: The presumedScore
>>         (0hard/-1soft) is corrupted because it is not the realScore
>>          (0hard/0soft).
>>         Presumed workingMemory:
>>           Score rule (soft-ReduceNullAssignment) has count (1) and
>>         weight total (1).
>>         Real workingMemory:
>>         at
>>         org.drools.planner.core.solution.director.DefaultSolutionDirector.assertWorkingScore(DefaultSolutionDirector.java:157)
>>         at
>>         org.drools.planner.core.solver.DefaultSolverScope.assertWorkingScore(DefaultSolverScope.java:105)
>>         at
>>         org.drools.planner.core.phase.AbstractSolverPhaseScope.assertWorkingScore(AbstractSolverPhaseScope.java:132)
>>         at
>>         org.drools.planner.core.constructionheuristic.greedyFit.DefaultGreedyFitSolverPhase.solve(DefaultGreedyFitSolverPhase.java:69)
>>         at
>>         org.drools.planner.core.solver.DefaultSolver.runSolverPhases(DefaultSolver.java:166)
>>         at
>>         org.drools.planner.core.solver.DefaultSolver.solve(DefaultSolver.java:138)
>>         ...
>>
>>     I've read this (https://issues.jboss.org/browse/JBRULES-3301),
>>     but it didn't help :
>>
>>         * I'm using IntConstraintOccurrence
>>         * I double check the soft constraint named
>>           "soft-ReduceNullAssignment" -- it's include all the cause.
>>         * I'm using Drools 5.3
>>
>>     After more digging, I think something is missing in
>>     DefaultSolutionDirector.java:153. The facts are added, but the
>>     planningEntity are not added.
>     They are added:
>
>              for (Object fact : getWorkingFacts()) {
>                 tmpWorkingMemory.insert(fact);
>             }
>
>         public Collection<Object> getWorkingFacts() {
>             return solutionDescriptor.getAllFacts(workingSolution); //
>     returns the problem facts + the initiliazed planningEntity's
>
>         }
>
>>     So when the score calculation is running, there is two different
>>     result. I'v place a breakpoint
>>     at DefaultSolutionDirector.java:157 and looking
>>     in tmpWorkingMemory->defaultEntryPoint->objectStore->identifyMap->table,
>>     I don't see the planningEntity.
>     That's weird.
>
>     Could you try this with the latest drools-planner-core
>     5.4.0.SNAPSHOT from the jboss nexus repository too?
>     You'll have to branch and upgrade your local code:
>     https://github.com/droolsjbpm/drools-planner/blob/master/drools-planner-distribution/src/main/assembly/filtered-resources/UpgradeFromPreviousVersionRecipe.txt
>
>     As a side affect, you'll notice that the exception message will be
>     much much clearer too, which will help in discovering the problem.
>
>>
>>     Here is the my rule :
>>
>>         rule "soft-ReduceNullAssignment"
>>         when
>>         $planif : PlanifEventAssignment( employee == null )
>>         then
>>                 insertLogical(new
>>         IntConstraintOccurrence("soft-ReduceNullAssignment",
>>         ConstraintType.NEGATIVE_SOFT,
>>                         1,
>>                         $planif));
>>         end
>>
>>
>>     Thanks
>>
>>     On Tue, Dec 6, 2011 at 11:12 AM, Geoffrey De Smet
>>     <ge0ffrey.spam at gmail.com <mailto:ge0ffrey.spam at gmail.com>> wrote:
>>
>>
>>
>>         Op 06-12-11 05:38, guyramirez schreef:
>>         > Still the same issue, starting with the construction
>>         heuristic phase. Please
>>         > let me know if you need more explanations in what I am
>>         trying to do.
>>         >
>>         > Here is the error. Please note that there is only one
>>         planning entity
>>         > (ShiftAssignment) object instance in this test.
>>         >
>>         > Total Staffing required: 8
>>         > 2011-12-05 22:21:49,627 [main] INFO  Solver started: time
>>         spend (0), score
>>         > (null), new best score (null), random seed (0).
>>         > ShiftAssignment: emp. id: 10 [st: 100, dur: 3]
>>         > ShiftAssignment: emp. id: 10 [st: 100, dur: 2]
>>         > ShiftAssignment: emp. id: 10 [st: 100, dur: 4]
>>         > ShiftAssignment: emp. id: 10 [st: 100, dur: 1]
>>         > 2011-12-05 22:21:49,678 [main] TRACE Building
>>         ConstraintOccurrence summary
>>         > 2011-12-05 22:21:49,678 [main] TRACE     Adding
>>         ConstraintOccurrence
>>         >
>>         (intervalRequirementCovered/NEGATIVE_HARD:[IntervalRequirement:
>>         interval:
>>         > 101, position id: 1, staffingRequired: 2, [ShiftAssignment:
>>         emp. id: 10 [st:
>>         > 100, dur: 1]]]=1)
>>         > 2011-12-05 22:21:49,678 [main] TRACE     Adding
>>         ConstraintOccurrence
>>         >
>>         (intervalRequirementCovered/NEGATIVE_HARD:[IntervalRequirement:
>>         interval:
>>         > 103, position id: 1, staffingRequired: 2, []]=2)
>>         > 2011-12-05 22:21:49,678 [main] TRACE     Adding
>>         ConstraintOccurrence
>>         >
>>         (intervalRequirementCovered/NEGATIVE_HARD:[IntervalRequirement:
>>         interval:
>>         > 102, position id: 1, staffingRequired: 2, []]=2)
>>         > 2011-12-05 22:21:49,678 [main] TRACE     Adding
>>         ConstraintOccurrence
>>         >
>>         (intervalRequirementCovered/NEGATIVE_HARD:[IntervalRequirement:
>>         interval:
>>         > 100, position id: 1, staffingRequired: 2, [ShiftAssignment:
>>         emp. id: 10 [st:
>>         > 100, dur: 1], ShiftAssignment: emp. id: 10 [st: 100, dur:
>>         1]]]=0)
>>         > 2011-12-05 22:21:49,678 [main] TRACE Building
>>         ConstraintOccurrence summary
>>         > 2011-12-05 22:21:49,678 [main] TRACE     Adding
>>         ConstraintOccurrence
>>         >
>>         (intervalRequirementCovered/NEGATIVE_HARD:[IntervalRequirement:
>>         interval:
>>         > 101, position id: 1, staffingRequired: 2, []]=2)
>>         > 2011-12-05 22:21:49,678 [main] TRACE     Adding
>>         ConstraintOccurrence
>>         >
>>         (intervalRequirementCovered/NEGATIVE_HARD:[IntervalRequirement:
>>         interval:
>>         > 103, position id: 1, staffingRequired: 2, []]=2)
>>         > 2011-12-05 22:21:49,678 [main] TRACE     Adding
>>         ConstraintOccurrence
>>         >
>>         (intervalRequirementCovered/NEGATIVE_HARD:[IntervalRequirement:
>>         interval:
>>         > 100, position id: 1, staffingRequired: 2, [ShiftAssignment:
>>         emp. id: 10 [st:
>>         > 100, dur: 1]]]=1)
>>         > 2011-12-05 22:21:49,678 [main] TRACE     Adding
>>         ConstraintOccurrence
>>         >
>>         (intervalRequirementCovered/NEGATIVE_HARD:[IntervalRequirement:
>>         interval:
>>         > 102, position id: 1, staffingRequired: 2, []]=2)
>>         > Exception in thread "main" java.lang.IllegalStateException: The
>>         > presumedScore (-5hard/-1soft) is corrupted because it is
>>         not the realScore
>>         > (-7hard/-1soft).
>>         > Presumed workingMemory:
>>         >    Score rule (intervalRequirementCovered) has count (4)
>>         and weight total
>>         > (5).
>>         > Real workingMemory:
>>         >    Score rule (intervalRequirementCovered) has count (4)
>>         and weight total
>>         > (7).
>>         So the score rule intervalRequirementCovered is to blame.
>>         >       at
>>         >
>>         org.drools.planner.core.solution.director.DefaultSolutionDirector.assertWorkingScore(DefaultSolutionDirector.java:157)
>>         >       at
>>         >
>>         org.drools.planner.core.solver.DefaultSolverScope.assertWorkingScore(DefaultSolverScope.java:105)
>>         >       at
>>         >
>>         org.drools.planner.core.phase.AbstractSolverPhaseScope.assertWorkingScore(AbstractSolverPhaseScope.java:132)
>>         >       at
>>         >
>>         org.drools.planner.core.constructionheuristic.greedyFit.decider.DefaultGreedyDecider.decideNextStep(DefaultGreedyDecider.java:65)
>>         >       at
>>         >
>>         org.drools.planner.core.constructionheuristic.greedyFit.DefaultGreedyFitSolverPhase.solve(DefaultGreedyFitSolverPhase.java:62)
>>         >       at
>>         >
>>         org.drools.planner.core.solver.DefaultSolver.runSolverPhases(DefaultSolver.java:166)
>>         >       at
>>         >
>>         org.drools.planner.core.solver.DefaultSolver.solve(DefaultSolver.java:138)
>>         >       at
>>         com.lfsoscience.planner.LfsoPlannerMain.execute(LfsoPlannerMain.java:36)
>>         >       at
>>         com.lfsoscience.planner.LfsoPlannerMain.main(LfsoPlannerMain.java:27)
>>         >
>>         >
>>         >
>>         > The drl:
>>         > rule "intervalRequirementCovered"
>>         Let's take a look
>>         >       when
>>         >               $intervalReq : IntervalRequirement($interval
>>         : interval, $position :
>>         > position, $staffingRequired : staffingRequired)
>>         >          $matchingShiftAssignments : ArrayList( size<=
>>         $staffingRequired )
>>         >                                                            
>>                   from collect ( ShiftAssignment(shiftStartTime<=
>>         $interval,
>>         > shiftEndTime>  $interval, position == $position) )
>>         I never used "from collect" in my examples yet.
>>         You probably stumbled upon a "statefull memory corruption
>>         bug" in drools.
>>
>>         First try this alternative way:
>>
>>                $intervalReq : IntervalRequirement($interval : interval,
>>         $position : position, $staffingRequired : staffingRequired)
>>                 $matchingShiftAssignmentSize : Number(intValue <=
>>         $staffingRequired) from accumulate(
>>                     $x : ShiftAssignment(shiftStartTime <= $interval,
>>         shiftEndTime > $interval, position == $position),
>>                     count($x)
>>                 )
>>
>>         If that works, file a ticket in issues.jboss.org
>>         <http://issues.jboss.org> for the project JBRULES
>>         about "statefull working memory corruption by using collect"
>>         and include that rule and - if possible - testdata how to
>>         reproduce it.
>>         >       then
>>         >               #actions
>>         >               insertLogical(new
>>         IntConstraintOccurrence("intervalRequirementCovered",
>>         > ConstraintType.NEGATIVE_HARD,
>>         >                                       $staffingRequired -
>>         $matchingShiftAssignments.size(),
>>         >                                       $intervalReq,
>>         $matchingShiftAssignments));
>>         > end
>>         > rule "hardConstraintsBroken"
>>         >          salience -1 // Do the other rules first (optional,
>>         for performance)
>>         >      when
>>         >          $hardTotal : Number() from accumulate(
>>         >              IntConstraintOccurrence(constraintType ==
>>         > ConstraintType.NEGATIVE_HARD, $weight : weight), sum($weight)
>>         >          )
>>         >      then
>>         >        
>>          scoreCalculator.setHardConstraintsBroken($hardTotal.intValue());
>>         > end
>>         > rule "softConstraintsBroken"
>>         >      when
>>         >          eval(true)
>>         >      then
>>         >          scoreCalculator.setSoftConstraintsBroken(1);
>>         > end
>>         >
>>         >
>>         >
>>         > The Planning Entity:
>>         >
>>         > @PlanningEntity
>>         > public class ShiftAssignment implements Cloneable {
>>         >       private Employee employee;
>>         >       private int day;
>>         >       private Position position;
>>         >       private TimeLengthPair timeLengthPair = null;
>>         >       // Immutable object. Does not need to be cloned when
>>         calling clone
>>         >       private List<TimeLengthPair>
>>          possibleShiftStartTimeLengthPairList;
>>         >       private Set<TimeLengthPair>
>>          possibleShiftStartTimeLengthPairSet;
>>         >
>>         >
>>         >       public ShiftAssignment(Employee employee, int day,
>>         Position position,
>>         > Set<TimeLengthPair>  shiftStartTimeLengthPairs) {
>>         >               this.employee = employee;
>>         >               this.day = day;
>>         >               this.position = position;
>>         >               this.possibleShiftStartTimeLengthPairSet = new
>>         > HashSet<TimeLengthPair>(shiftStartTimeLengthPairs);
>>         >       }
>>         >
>>         >       public int getShiftStartTime() {
>>         >               return this.timeLengthPair != null ?
>>         this.timeLengthPair.getStartTime() :
>>         > -1;
>>         >       }
>>         >
>>         >       public int getShiftEndTime() {
>>         >               return this.timeLengthPair != null ?
>>         this.timeLengthPair.getStartTime() +
>>         > this.timeLengthPair.getLength() : -1;
>>         >       }
>>         >
>>         >       public void
>>         setShiftStartTimeLengthPair(TimeLengthPair timeLengthPair) {
>>         >               this.timeLengthPair = timeLengthPair;
>>         >               System.out.println(this);
>>         >       }
>>         looks good
>>         >
>>         >       public void
>>         addPossibleShiftStartTimeLengthPair(TimeLengthPair
>>         > timeLengthPair) {
>>         >              
>>         this.possibleShiftStartTimeLengthPairSet.add(timeLengthPair);
>>         >               // Clear the list since the Set has changed.
>>         The list will be recreated
>>         > from the set when needed (see
>>         getPossibleShiftStartTimeLengthPairs())
>>         >               this.possibleShiftStartTimeLengthPairList = null;
>>         >       }
>>         this isn't called during planning I presume?
>>         >       @PlanningVariable
>>         >       @ValueRangeFromPlanningEntityProperty(propertyName =
>>         > "possibleShiftStartTimeLengthPairs")
>>         >       public TimeLengthPair getShiftStartTimeLengthPair() {
>>         >               return this.timeLengthPair;
>>         >       }
>>         looks good
>>         >       public List<TimeLengthPair>
>>          getPossibleShiftStartTimeLengthPairs() {
>>         >               if (this.possibleShiftStartTimeLengthPairList
>>         == null) {
>>         >                      
>>         this.possibleShiftStartTimeLengthPairList =  new
>>         >
>>         ArrayList<TimeLengthPair>(this.possibleShiftStartTimeLengthPairSet);
>>         >               }
>>         >               return this.possibleShiftStartTimeLengthPairList;
>>         >       }
>>         >
>>         >       public Employee getEmployee() {
>>         >               return this.employee;
>>         >       }
>>         >
>>         >       public int getDay() {
>>         >               return this.day;
>>         >       }
>>         >
>>         >       public Position getPosition() {
>>         >               return this.position;
>>         >       }
>>         >
>>         >       public boolean solutionEquals(Object o) {
>>         >          if (this == o) {
>>         >              return true;
>>         >          } else if (o instanceof ShiftAssignment) {
>>         >               ShiftAssignment other = (ShiftAssignment) o;
>>         >              return new EqualsBuilder()
>>         >                      .append(this.employee, other.employee)
>>         >                      .append(this.position, other.position)
>>         >                      .append(this.timeLengthPair,
>>         other.timeLengthPair)
>>         >                      .isEquals();
>>         >          } else {
>>         >              return false;
>>         >          }
>>         >      }
>>         >
>>         >       public int solutionHashCode() {
>>         >               HashCodeBuilder hashCodeBuilder = new
>>         HashCodeBuilder();
>>         >               hashCodeBuilder.append(getClass())
>>         >                  .append(this.employee)
>>         >                  .append(this.position)
>>         >                  .append(this.timeLengthPair);
>>         >               return hashCodeBuilder.toHashCode();
>>         >      }
>>         >
>>         >       @Override
>>         >       public Object clone() throws CloneNotSupportedException {
>>         >               return super.clone();
>>         >       }
>>         >
>>         >       @Override
>>         >       public String toString() {
>>         >               StringBuilder sb = new StringBuilder();
>>         >               sb.append("ShiftAssignment: ")
>>         >                       .append("emp. id:
>>         ").append(this.employee.getId())
>>         >                       .append(" ")
>>         >                       .append(this.timeLengthPair != null ?
>>         this.timeLengthPair.toString() :
>>         > "Not Initialized");
>>         >               return sb.toString();
>>         >       }
>>         >
>>         >       @Override
>>         >       public int hashCode() {
>>         >               return solutionHashCode();
>>         > //            return super.hashCode();
>>         >       }
>>         >
>>         >       @Override
>>         >       public boolean equals(Object obj) {
>>         >               return solutionEquals(obj);
>>         > //            return super.equals(obj);
>>         >       }
>>         > }
>>         >
>>         >
>>         > --
>>         > View this message in context:
>>         http://drools.46999.n3.nabble.com/Planner-5-3-Final-presumedScore-is-corrupted-when-using-update-on-the-rules-working-memory-tp3546932p3563446.html
>>         > Sent from the Drools: User forum mailing list archive at
>>         Nabble.com.
>>         > _______________________________________________
>>         > rules-users mailing list
>>         > rules-users at lists.jboss.org
>>         <mailto:rules-users at lists.jboss.org>
>>         > https://lists.jboss.org/mailman/listinfo/rules-users
>>         >
>>
>>         --
>>         With kind regards,
>>         Geoffrey De Smet
>>
>>
>>         _______________________________________________
>>         rules-users mailing list
>>         rules-users at lists.jboss.org <mailto:rules-users at lists.jboss.org>
>>         https://lists.jboss.org/mailman/listinfo/rules-users
>>
>>
>>
>>
>>     -- 
>>     Patrik Dufresne
>>
>>
>>     _______________________________________________
>>     rules-users mailing list
>>     rules-users at lists.jboss.org  <mailto:rules-users at lists.jboss.org>
>>     https://lists.jboss.org/mailman/listinfo/rules-users
>
>     -- 
>     With kind regards,
>     Geoffrey De Smet
>
>
>     _______________________________________________
>     rules-users mailing list
>     rules-users at lists.jboss.org <mailto:rules-users at lists.jboss.org>
>     https://lists.jboss.org/mailman/listinfo/rules-users
>
>
>
>
> -- 
> Patrik Dufresne
>
>
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-users

-- 
With kind regards,
Geoffrey De Smet

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-users/attachments/20111207/d7b9a2ea/attachment.html 


More information about the rules-users mailing list