<html><body><div style="color:#000; background-color:#fff; font-family:tahoma, new york, times, serif;font-size:10pt">Thank you for the quick response, Geoffrey.<br><br>So basically what I do is correct?<br><br>I'm still curious why<br>a) 3 planes, 2 techs 4 periods ends in 3 seconds with<br><span class="tab">&nbsp;&nbsp;&nbsp; </span>isEveryProblemFactChangeProcessed: true<br><span class="tab">&nbsp;&nbsp;&nbsp; </span>isTerminateEarly: false<br><span class="tab">&nbsp;&nbsp;&nbsp; </span>score: 0<br><br>b) 3 planes, 3 techs 4 periods keeps running for ?? time<br><br>I changed the termination parameter to 60 seconds.<br>After 60 seconds best-solution gives a score of 0 but my planningEntities have no period assigned; only a technician.<br><br><br><div>&nbsp;</div><div>-----------------<br>http://www.codessentials.com - Your essential software, for free!<br>Follow us at http://twitter.com/#!/Codessentials<br></div>  <div style="font-family: tahoma, new
 york, times, serif; font-size: 10pt;"> <div style="font-family: times new roman, new york, times, serif; font-size: 12pt;"> <div dir="ltr"> <font face="Arial" size="2"> <hr size="1">  <b><span style="font-weight:bold;">From:</span></b> Geoffrey De Smet &lt;ge0ffrey.spam@gmail.com&gt;<br> <b><span style="font-weight: bold;">To:</span></b> rules-users@lists.jboss.org <br> <b><span style="font-weight: bold;">Sent:</span></b> Friday, August 31, 2012 3:29 PM<br> <b><span style="font-weight: bold;">Subject:</span></b> Re: [rules-users] Best model for planning? technicians, airplanes and shifts<br> </font> </div> <br>Op 31-08-12 15:07, Michiel Vermandel schreef:<br>&gt; Hi, me once more.<br>&gt;<br>&gt; I guess you figured out by now that I am quite a newbie to Drools<br>&gt; (planning).<br>&gt; Problem is I need to write a POC in max 3 to 4 days...<br>&gt; I'm drifting, so please help...<br>&gt;<br>&gt; I have written a basic solution for planning
 plane-maintenance.<br>&gt; I stripped it to it's very basics and it works... if I keep the number<br>&gt; of planes, periods and technicians to a very minimum.<br>&gt; I removed all additional constraints like skill matching and<br>&gt; availability during a period...<br>&gt;<br>&gt; Planning maintenance for 3 planes with each 2 required technicians, 4<br>&gt; available periods and a list of 10 available technicians delivers a<br>&gt; solution in about 3 seconds.<br>It probably stopped early because basically all solutions had been seen.<br><br>&gt; Simply increasing the number of technicians per plane from 2 to 3<br>&gt; results in an indefinite solving time (I did not wait longer than a few<br>&gt; minutes).<br>you got:<br>&lt;maximumSecondsSpend&gt;700&lt;/maximumSecondsSpend&gt;<br>so it will run for over 11 minutes.<br>Turn that to just 60 seconds (or see manual about alternative <br>termination methods).<br><br>The problem is NP-complete, so as
 you scale up to thousands (and more) <br>planes/techs/periods, no software (and certainly no human being) can <br>find the optimal solution in reasonable time (see first chatper in <br>manual). Planner will find you the best solution in the time you (can) <br>give it.<br><br>&gt; Decreasing the numbers obviously works, at an elapsed time slightly<br>&gt; under 3 seconds.<br>&gt;<br>&gt; I finally need to plan about 500 plane maintenance jobs (3 to 4<br>&gt; technicians per maintenance job) over 12 available periods with about<br>&gt; 400 available technicians..<br>&gt; So there must be something wrong/incomplete in my solution.<br>&gt;<br>&gt; What I did:<br>&gt;<br>&gt; I have created a planningEntity MaintenanceTask with two planning<br>&gt; variables (technician and period)&nbsp; and a simple rule file.<br>&gt; (See all below)<br>&gt; Running this solution thus results in such poor solving time.<br>&gt;<br>&gt; Can you please advice me in what I am
 doing wrong?<br>&gt;<br>&gt; Many thanks!!<br>&gt;<br>&gt; PlanningEntity (MaintenanceTask .java):<br>&gt;<br>&gt; @PlanningEntity(difficultyWeightFactoryClass =<br>&gt; TaskDifficultyWeightFactory.class)<br>&gt; public class MaintenanceTask {<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; private Period period;<br>&gt;&nbsp; &nbsp; &nbsp; private Project project;<br>&gt;&nbsp; &nbsp; &nbsp; private Technician technician;<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public MaintenanceTask (Project aProject) {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.project = aProject;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public String getId(){<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return project.getId()+"-"+hashCode();<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; @PlanningVariable<br>&gt;&nbsp; &nbsp; &nbsp; @ValueRange(type = ValueRangeType.FROM_SOLUTION_PROPERTY,<br>&gt; solutionProperty = "technicians")<br>&gt;&nbsp; &nbsp;
 &nbsp; public Technician getTechnician() {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return technician;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public void setTechnician(Technician aTechnician) {<br>&gt;&nbsp; &nbsp; &nbsp; this.technican= aTechnician;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; @PlanningVariable<br>&gt;&nbsp; &nbsp; &nbsp; @ValueRange(type = ValueRangeType.FROM_SOLUTION_PROPERTY,<br>&gt; solutionProperty = "periods")<br>&gt;&nbsp; &nbsp; &nbsp; public Period getPeriod() {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return period;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public void setPeriod(Period aPeriod) {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.period = aPeriod;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public String getPeriodId(){<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return period == null ? null :
 period.getId();<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public String getProjectId(){<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return project == null ? null : project.getId();<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp;  public MaintenanceTask clone() {<br>&gt; MaintenanceTask clone = new MaintenanceTask (project);<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; clone.period = this.period;<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; clone.technician= this.technician;<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return clone;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt; }<br>&gt;<br>&gt; Project.java<br>&gt;<br>&gt; public class Project {<br>&gt;&nbsp; &nbsp; &nbsp; private Plane plane;<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public Project(Plane aPlane) {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.plane = aPlane;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public Plane getPlane() {<br>&gt;&nbsp;
 &nbsp; &nbsp; &nbsp; &nbsp; return plane;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public String getId() {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return getPlane().getName();<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public int getTechnicianLoad(){<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return getPlane().getTechnicianLoad();<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public List&lt;MaintenanceTask&gt; getTasks() {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; List&lt;MaintenanceTask&gt; tasks = new ArrayList&lt;MaintenanceTask&gt;();<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt; getTechnicianLoad(); i++) {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tasks.add(new MaintenanceTask(this));<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return tasks;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt; }<br>&gt;<br>&gt;
 Technician.java and Period.java are at this moment basically just<br>&gt; classes having an getId and getName method, nothing more.<br>&gt; Plane.java has a method getTechnicianLoad that returns the number of<br>&gt; required technicians for the maintenance.<br>&gt;<br>&gt; This is the config file (basically copy from one of the examples)<br>&gt;<br>&gt; &lt;?xml version="1.0" encoding="UTF-8"?&gt;<br>&gt; &lt;solver&gt;<br>&gt;&nbsp; &nbsp; &lt;!-- Domain model configuration --&gt;<br>&gt;&nbsp; &nbsp; &lt;solutionClass&gt;be.axi.planner.domain.MaintenanceSchedule&lt;/solutionClass&gt;<br>&gt;<br>&gt; &lt;planningEntityClass&gt;be.axi.planner.domain.MaintenanceTask&lt;/planningEntityClass&gt;<br>&gt;<br>&gt;&nbsp; &nbsp; &lt;!-- Score configuration --&gt;<br>&gt;&nbsp; &nbsp; &lt;scoreDirectorFactory&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &lt;scoreDefinitionType&gt;SIMPLE&lt;/scoreDefinitionType&gt;<br>&gt;&nbsp; &nbsp; &nbsp;
 &lt;scoreDrl&gt;/maintenancePlannerRules.drl&lt;/scoreDrl&gt;<br>&gt;&nbsp; &nbsp; &lt;/scoreDirectorFactory&gt;<br>&gt;<br>&gt;&nbsp; &nbsp; &lt;termination&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &lt;maximumSecondsSpend&gt;700&lt;/maximumSecondsSpend&gt;<br>&gt;&nbsp; &nbsp; &lt;/termination&gt;<br>&gt;<br>&gt;&nbsp; &nbsp; &lt;constructionHeuristic&gt;<br>&gt;<br>&gt; &lt;constructionHeuristicType&gt;FIRST_FIT_DECREASING&lt;/constructionHeuristicType&gt;<br>&gt;<br>&gt; &lt;constructionHeuristicPickEarlyType&gt;FIRST_LAST_STEP_SCORE_EQUAL_OR_IMPROVING&lt;/constructionHeuristicPickEarlyType&gt;<br>&gt;&nbsp; &nbsp; &lt;/constructionHeuristic&gt;<br>&gt;&nbsp; &nbsp; &lt;localSearch&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &lt;selector&gt;<br>&gt;<br>&gt; &lt;moveFactoryClass&gt;org.drools.planner.core.move.generic.GenericChangeMoveFactory&lt;/moveFactoryClass&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- GenericChangeMoveFactory is the generic form of<br>&gt;
 RowChangeMoveFactory: --&gt;<br>&gt;<br>&gt; &lt;!--&lt;moveFactoryClass&gt;org.drools.planner.examples.nqueens.solver.move.factory.RowChangeMoveFactory&lt;/moveFactoryClass&gt;--&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &lt;/selector&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &lt;acceptor&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &lt;solutionTabuSize&gt;1000&lt;/solutionTabuSize&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &lt;planningEntityTabuSize&gt;7&lt;/planningEntityTabuSize&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &lt;/acceptor&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &lt;forager&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &lt;minimalAcceptedSelection&gt;800&lt;/minimalAcceptedSelection&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &lt;/forager&gt;<br>&gt;&nbsp; &nbsp; &lt;/localSearch&gt;<br>&gt; &lt;/solver&gt;<br>&gt;<br>&gt; this is the rules file:<br>&gt;<br>&gt; package org.drools.planner.examples.pas.solver;<br>&gt;&nbsp; &nbsp; &nbsp; dialect "java"<br>&gt;<br>&gt; import
 org.drools.planner.core.score.buildin.simple.SimpleScoreHolder;<br>&gt; import org.drools.planner.core.score.constraint.IntConstraintOccurrence;<br>&gt; import<br>&gt; org.drools.planner.core.score.constraint.UnweightedConstraintOccurrence<br>&gt; import org.drools.planner.core.score.constraint.ConstraintType;<br>&gt;<br>&gt; import be.axi.planner.domain.MaintenanceTask;<br>&gt;<br>&gt; global SimpleScoreHolder scoreHolder;<br>&gt;<br>&gt; //<br>&gt; ############################################################################<br>&gt; // Hard constraints<br>&gt; //<br>&gt; ############################################################################<br>&gt;<br>&gt; rule "noMultipleAssignmentsInOnePeriod"<br>&gt;&nbsp; &nbsp; &nbsp; when<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $t1 : MaintenanceTask($id : id, $periodId : periodId,<br>&gt; $technician : technician )<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $t2 : MaintenanceTask(id != $id,&nbsp; periodId
 == $periodId,<br>&gt; technician == $technician)<br>&gt;&nbsp; &nbsp; &nbsp; then<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; insertLogical(new<br>&gt; UnweightedConstraintOccurrence("noMultipleAssignmentsInOnePeriod", $t1,<br>&gt; $t2));<br>&gt; end<br>&gt;<br>&gt; rule "tasksInSameProjectMustBeInSamePeriod"<br>&gt;&nbsp; &nbsp; &nbsp; when<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $t1 : MaintenanceTask($id : id, $periodId : periodId,<br>&gt; $projectId : projectId )<br>&gt; $t2 : MaintenanceTask(id != $id,&nbsp; periodId != $periodId, projectId ==<br>&gt; $projectId)<br>&gt;&nbsp; &nbsp; &nbsp; then<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; insertLogical(new<br>&gt; UnweightedConstraintOccurrence("tasksInSameProjectMustBeInSamePeriod",<br>&gt; $t1, $t2));<br>&gt; end<br>&gt;<br>&gt; //<br>&gt; ############################################################################<br>&gt; // Calculate score<br>&gt; //<br>&gt;
 ############################################################################<br>&gt;<br>&gt; rule "hardConstraintsBroken"<br>&gt;&nbsp; &nbsp; &nbsp; when<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $occurrenceCount : Number() from accumulate(<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $unweightedConstraintOccurrence :<br>&gt; UnweightedConstraintOccurrence(),<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; count($unweightedConstraintOccurrence)<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )<br>&gt; then<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; scoreHolder.setScore(- $occurrenceCount.intValue());<br>&gt; end<br>&gt;<br>&gt; Solution file:<br>&gt;<br>&gt; package be.axi.planner.domain;<br>&gt;<br>&gt; import java.util.ArrayList;<br>&gt; import java.util.Collection;<br>&gt; import java.util.List;<br>&gt;<br>&gt; import<br>&gt; org.drools.planner.api.domain.solution.PlanningEntityCollectionProperty;<br>&gt; import
 org.drools.planner.core.score.buildin.simple.SimpleScore;<br>&gt; import org.drools.planner.core.solution.Solution;<br>&gt;<br>&gt;<br>&gt; public class MaintenanceSchedule implements Solution&lt;SimpleScore&gt;{<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; private SimpleScore score;<br>&gt;&nbsp; &nbsp; &nbsp; private List&lt;MaintenanceTask&gt; maintenanceTasks;<br>&gt;&nbsp; &nbsp; &nbsp; private List&lt;Period&gt; periods;<br>&gt;&nbsp; &nbsp; &nbsp; private List&lt;Technician&gt; technicians;<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public MaintenanceSchedule cloneSolution() {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MaintenanceSchedule clone = new MaintenanceSchedule();<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; clone.periods = this.periods;<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; clone.technicians = this.technicians;<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; List&lt;MaintenanceTask&gt; clonedTasks = new ArrayList&lt;MaintenanceTask&gt;(<br>&gt;&nbsp; &nbsp;
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; maintenanceTasks.size());<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (MaintenanceTask task : maintenanceTasks) {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MaintenanceTask clonedTask = task.clone();<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; clonedTasks.add(clonedTask);<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; clone.maintenanceTasks = clonedTasks;<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; clone.score = this.score;<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return clone;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public Collection&lt;? extends Object&gt; getProblemFacts() {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("&gt;&gt;getting problemfacts");<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; List&lt;Object&gt; facts = new ArrayList&lt;Object&gt;();<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp;
 &nbsp; facts.addAll(periods);<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; facts.addAll(technicians);<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Do not add the planning entity's (maintenaceTasks) because<br>&gt; that will be done automatically<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return facts;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public SimpleScore getScore() {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return this.score;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public void setScore(SimpleScore aScore) {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.score = aScore;<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (aScore != null){<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("Score set to " + aScore.getScore());<br>&gt; }<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; @PlanningEntityCollectionProperty<br>&gt;&nbsp; &nbsp; &nbsp; public List&lt;MaintenanceTask&gt;
 getMaintenanceTasks() {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("getting tasks: #" +maintenanceTasks.size());<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return maintenanceTasks;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public void setMaintenanceTasks(List&lt;MaintenanceTask&gt;<br>&gt; aMaintenanceTasks) {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("setting tasks");<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.maintenanceTasks = aMaintenanceTasks;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public void setTechnicians(List&lt;Technician&gt; aTechnicians) {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("setting Technicians");<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.technicians = aTechnicians;<br>&gt; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public List&lt;Technician&gt; getTechnicians() {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
 System.out.println("Getting Technicians: #"+technicians.size());<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return technicians;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public List&lt;Period&gt; getPeriods() {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("getting periods");<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return periods;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt;&nbsp; &nbsp; &nbsp; public void setPeriods(List&lt;Period&gt; periods) {<br>&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.periods = periods;<br>&gt;&nbsp; &nbsp; &nbsp; }<br>&gt;<br>&gt; }<br>&gt;<br>&gt;<br>&gt;<br>&gt;<br>&gt; -----------------<br>&gt; <a href="http://www.codessentials.com/" target="_blank">http://www.codessentials.com</a> - Your essential software, for free!<br>&gt; Follow us at <a href="http://twitter.com/#!/Codessentials" target="_blank">http://twitter.com/#!/Codessentials</a><br>&gt;
 ------------------------------------------------------------------------<br>&gt; *From:* Geoffrey De Smet &lt;<a ymailto="mailto:ge0ffrey.spam@gmail.com" href="mailto:ge0ffrey.spam@gmail.com">ge0ffrey.spam@gmail.com</a>&gt;<br>&gt; *To:* <a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a><br>&gt; *Sent:* Friday, August 31, 2012 10:54 AM<br>&gt; *Subject:* Re: [rules-users] Best model for planning? technicians,<br>&gt; airplanes and shifts<br>&gt;<br>&gt; Op 31-08-12 09:46, Michiel Vermandel schreef:<br>&gt;&nbsp; &gt; Thank you for the response.<br>&gt;&nbsp; &gt; I think I forgot one level of complexity (?):<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; The moment of maintenance of a plane is not fixed.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; We have 12 "periods" per year for maintenance.<br>&gt;&nbsp; &gt; One period every month.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; We need to make the
 planning in such way that the list of planes is<br>&gt;&nbsp; &gt; planned somewhere in these 12 periods.<br>&gt;&nbsp; &gt; But it is not important that a specific plane is maintained at a<br>&gt;&nbsp; &gt; specific period.<br>&gt;&nbsp; &gt; It has though a calendar of unavailability.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; So the job (==Shift) of the Task (==ShiftAssignment) has no hard<br>&gt;&nbsp; &gt; constraint on period.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; We need to find that combination with the best match between required<br>&gt;&nbsp; &gt; skills for the job and available technicians.<br>&gt;&nbsp; &gt; It's better to plan the job on a later period if at that time a more<br>&gt;&nbsp; &gt; skilled technician is available.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; I hope this is a bit clear.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; So, given this addition, should I take as planning variables:<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; 1) Period (List
 of 12 periods)<br>&gt;&nbsp; &gt; 2) Technician<br>&gt;<br>&gt; Good idea<br>&gt;<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; Then use period to check availability on both plane and technician<br>&gt;&nbsp; &gt; (hard-constraint)<br>&gt; I see 3:<br>&gt; - plane availability<br>&gt; - technician conflicts (2 tasks at the same time)<br>&gt; - technician availability<br>&gt;&nbsp; &gt; Then give a better weight on skill-match (soft-constrain)?<br>&gt;<br>&gt; yes (and possible others, such as work load, technician desires, ...)<br>&gt;<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; Thank you.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; Michiel<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; -----------------<br>&gt;&nbsp; &gt; <a href="http://www.codessentials.com/" target="_blank">http://www.codessentials.com</a> - Your essential software, for free!<br>&gt;&nbsp; &gt; Follow us at <a href="http://twitter.com/#!/Codessentials"
 target="_blank">http://twitter.com/#!/Codessentials</a><br>&gt;&nbsp; &gt; ------------------------------------------------------------------------<br>&gt;&nbsp; &gt; *From:* Geoffrey De Smet &lt;<a ymailto="mailto:ge0ffrey.spam@gmail.com" href="mailto:ge0ffrey.spam@gmail.com">ge0ffrey.spam@gmail.com</a><br>&gt; &lt;mailto:<a ymailto="mailto:ge0ffrey.spam@gmail.com" href="mailto:ge0ffrey.spam@gmail.com">ge0ffrey.spam@gmail.com</a>&gt;&gt;<br>&gt;&nbsp; &gt; *To:* <a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a> &lt;mailto:<a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a>&gt;<br>&gt;&nbsp; &gt; *Sent:* Friday, August 31, 2012 9:08 AM<br>&gt;&nbsp; &gt; *Subject:* Re: [rules-users] Best model for planning? technicians,<br>&gt;&nbsp; &gt; airplanes and shifts<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; Op 30-08-12
 18:02, mvermand schreef:<br>&gt;&nbsp; &gt;&nbsp; &gt; Hi,<br>&gt;&nbsp; &gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt; I'd like some advice on how to make my model.<br>&gt;&nbsp; &gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt; I need to plan maintenance-schedules for - let's say - airplanes.<br>&gt;&nbsp; &gt;&nbsp; &gt; Constraints are:<br>&gt;&nbsp; &gt;&nbsp; &gt; - planes are only at given moments available for maintenance (when<br>&gt; not in<br>&gt;&nbsp; &gt;&nbsp; &gt; the air ;-)<br>&gt;&nbsp; &gt;&nbsp; &gt; - maintenance of a planes requires a number of techniciens (with<br>&gt; specific<br>&gt;&nbsp; &gt;&nbsp; &gt; skills).<br>&gt;&nbsp; &gt;&nbsp; &gt; - techniciens have skills and also shifts and vacation.<br>&gt;&nbsp; &gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; Sounds like the nurse rostering example in Planner :)<br>&gt;&nbsp; &gt; In nurse rostering, such a Shift has a ShiftDate and a ShiftType.<br>&gt;&nbsp; &gt; The
 difference is, you need to assign jobs instead of shifts.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt; Now, first I tought to make the maintenance of a plane the<br>&gt;&nbsp; &gt; planningEntity.<br>&gt;&nbsp; &gt;&nbsp; &gt; But I did not know how to populate and match the techniciens.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; I wouldn't make plane the planningEntity either, it's on the one side of<br>&gt;&nbsp; &gt; the manyToOne relation.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt; So, second I tought to make a new Task-class the planningEntity.<br>&gt;&nbsp; &gt;&nbsp; &gt; A Task is a job that needs to be done by a technicien with specific<br>&gt;&nbsp; &gt; skills.<br>&gt;&nbsp; &gt;&nbsp; &gt; Maintaining a plane requires then a number of tasks.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; Good idea. In nurse rostering, a Task is called a ShiftAssignment.<br>&gt;&nbsp; &gt; You can generate all Tasks in advance based
 on the Planes and their jobs<br>&gt;&nbsp; &gt; and the number of technicians needed by each job.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; I recommend to make separate Task instances for multiple technicians<br>&gt;&nbsp; &gt; that perform the same job together on the same plane. In nurse rostering<br>&gt;&nbsp; &gt; there are also multiple ShiftAssignments (=tasks) per Shift (=job).<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt; If I choose this model, I think I'll have to pass two Plannings<br>&gt;&nbsp; &gt; variables to<br>&gt;&nbsp; &gt;&nbsp; &gt; the Task planningEntity:<br>&gt;&nbsp; &gt;&nbsp; &gt; 1) a Maintenance-fact (Plane + Period + list of required tasks) and<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; I don't think this is a planner variable on the planning entity Task.<br>&gt;&nbsp; &gt; It really defines the Task: what job on what plane (and some of sort of<br>&gt;&nbsp; &gt;
 requiredTechnicanCountIndex)<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt; 2) a Technicien-fact (?)<br>&gt;&nbsp; &gt; This is a planning variable.<br>&gt;&nbsp; &gt; You're assigning task to techinicians.<br>&gt;&nbsp; &gt; Each task has exactly 1 technician (because a job has multiple tasks,<br>&gt;&nbsp; &gt; one per required technician).<br>&gt;&nbsp; &gt; Each technician can work on multiple tasks, but the hard/soft<br>&gt;&nbsp; &gt; constraints make sure that it's not at the same time.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt; Then I'll need to check if availabity of plane and availability of<br>&gt;&nbsp; &gt;&nbsp; &gt; technicien match and also skill-requirement of task and skills of<br>&gt;&nbsp; &gt;&nbsp; &gt; technicien.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; Yep, with constraints<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt; Do you think this second model is the right
 one?<br>&gt;&nbsp; &gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt; Will it perform well?<br>&gt;&nbsp; &gt;&nbsp; &gt; =&gt; ? matching all combinations of plane availabilty and<br>&gt;&nbsp; &gt;&nbsp; &gt; techniciens-availability and -skills.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; It should, see the nurse rostering problem.<br>&gt;&nbsp; &gt; In Planner 5.5.0.Beta1, I would add a filter on the swap move selector<br>&gt;&nbsp; &gt; to prevent it from swapping 2 technicians assigned to different tasks on<br>&gt;&nbsp; &gt; the same job.<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;<br>&gt; <a href="https://github.com/droolsjbpm/drools-planner/blob/master/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/solver/move/DifferentCourseSwapMoveFilter.javatd"
 target="_blank">https://github.com/droolsjbpm/drools-planner/blob/master/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/solver/move/DifferentCourseSwapMoveFilter.javatd</a><br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt; Thanks in advance<br>&gt;&nbsp; &gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;&nbsp; &gt; --<br>&gt;&nbsp; &gt;&nbsp; &gt; View this message in context:<br>&gt;&nbsp; &gt; <a href="http://drools.46999.n3.nabble.com/Best-model-for-planning-tp4019464.html" target="_blank">http://drools.46999.n3.nabble.com/Best-model-for-planning-tp4019464.html</a><br>&gt;&nbsp; &gt;&nbsp; &gt; Sent from the Drools: User forum mailing list archive at Nabble.com<br>&gt;&nbsp; &gt; &lt;<a href="http://nabble.com/" target="_blank">http://nabble.com/</a>&gt;.<br>&gt;&nbsp; &gt;&nbsp; &gt;
 _______________________________________________<br>&gt;&nbsp; &gt;&nbsp; &gt; rules-users mailing list<br>&gt;&nbsp; &gt;&nbsp; &gt; <a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a> &lt;mailto:<a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a>&gt;<br>&gt; &lt;mailto:<a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a> &lt;mailto:<a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a>&gt;&gt;<br>&gt;&nbsp; &gt;&nbsp; &gt; <a href="https://lists.jboss.org/mailman/listinfo/rules-users" target="_blank">https://lists.jboss.org/mailman/listinfo/rules-users</a><br>&gt;&nbsp; &gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;
 _______________________________________________<br>&gt;&nbsp; &gt; rules-users mailing list<br>&gt;&nbsp; &gt; <a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a> &lt;mailto:<a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a>&gt;<br>&gt; &lt;mailto:<a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a> &lt;mailto:<a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a>&gt;&gt;<br>&gt;&nbsp; &gt; <a href="https://lists.jboss.org/mailman/listinfo/rules-users" target="_blank">https://lists.jboss.org/mailman/listinfo/rules-users</a><br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt;<br>&gt;&nbsp; &gt; _______________________________________________<br>&gt;&nbsp;
 &gt; rules-users mailing list<br>&gt;&nbsp; &gt; <a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a> &lt;mailto:<a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a>&gt;<br>&gt;&nbsp; &gt; <a href="https://lists.jboss.org/mailman/listinfo/rules-users" target="_blank">https://lists.jboss.org/mailman/listinfo/rules-users</a><br>&gt;&nbsp; &gt;<br>&gt;<br>&gt;<br>&gt; _______________________________________________<br>&gt; rules-users mailing list<br>&gt; <a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a> &lt;mailto:<a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a>&gt;<br>&gt; <a href="https://lists.jboss.org/mailman/listinfo/rules-users"
 target="_blank">https://lists.jboss.org/mailman/listinfo/rules-users</a><br>&gt;<br>&gt;<br>&gt;<br>&gt;<br>&gt; _______________________________________________<br>&gt; rules-users mailing list<br>&gt; <a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a><br>&gt; <a href="https://lists.jboss.org/mailman/listinfo/rules-users" target="_blank">https://lists.jboss.org/mailman/listinfo/rules-users</a><br>&gt;<br><br><br>_______________________________________________<br>rules-users mailing list<br><a ymailto="mailto:rules-users@lists.jboss.org" href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a><br><a href="https://lists.jboss.org/mailman/listinfo/rules-users" target="_blank">https://lists.jboss.org/mailman/listinfo/rules-users</a><br><br><br> </div> </div>  </div></body></html>