<html><body><div style="color:#000; background-color:#fff; font-family:arial, helvetica, sans-serif;font-size:10pt">Hi,<br><br>I need to group a number of entities together and I'm not sure if my rule is optimal.<br><br>My planning entities represent maintenance tasks on airplanes.<br>Every planning entity is a discreet task (check tires, refuel, check engines...) but the maintenance of an airplane exists of a number of these tasks and they need to be grouped together.<br>Every task has a duration depending on its type (checking engine takes longer than checking tires).<br>The optimal solution is that all tasks of a maintenance are in the smallest amount of time (time between start of first task till end of last task).<br>Though, the smaller the better, at least all tasks should be sequential (without gaps between the tasks).<br>Dependencies on the tasks are availability of the plain, availability of the technicians...<br><br>(The rules beneath only
 check that the tasks are chained together, not (yet) that the time span is minimal =&gt; I thought to make a soft-constraint for that).<br><br>First I had this rule:<br><br>rule "tasksInSameMaintenanceJobMustBeChained"<br>&nbsp;&nbsp;&nbsp; when<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $task : Task( $jobId: jobId )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; not ( Task( jobId== $jobId, id != $task.id, ($task.startPeriodId-1) &lt;= endPeriodId &amp;&amp; ($task.endPeriodId+1) &gt;= startPeriodId ) )<br>&nbsp;&nbsp;&nbsp; then // we have a gap!<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; insertLogical(new IntConstraintOccurrence("tasksInSameMaintenanceJobMustBeChained", ConstraintType.NEGATIVE_HARD, Importance.chainedPeriod, $jobId, $task));<br>end<br><div><br><span></span></div><div style="color: rgb(0, 0, 0); font-size: 13.3333px; font-family: arial,helvetica,sans-serif; background-color: transparent; font-style: normal;"><span>After adding
 this rule I started struggling with what I believe is to be a score trap.</span></div><div style="color: rgb(0, 0, 0); font-size: 13.3333px; font-family: arial,helvetica,sans-serif; background-color: transparent; font-style: normal;"><span>After advice from Geoffrey and reading some more, I thought my rule suffered from having a penalty which did not change depending on the amount of spread of the tasks.</span></div><div style="color: rgb(0, 0, 0); font-size: 13.3333px; font-family: arial,helvetica,sans-serif; background-color: transparent; font-style: normal;"><br><span></span></div><div style="color: rgb(0, 0, 0); font-size: 13.3333px; font-family: arial,helvetica,sans-serif; background-color: transparent; font-style: normal;"><span>So I rewrote the task to:</span></div><div style="color: rgb(0, 0, 0); font-size: 13.3333px; font-family: arial,helvetica,sans-serif; background-color: transparent; font-style: normal;">(I have now put all
 <span>MaintenanceJobs into the working memory and I created a Class TaskSet() which is capable of calculating the nr of periods between all tasks of a job = gapCount)</span></div><div style="color: rgb(0, 0, 0); font-size: 13.3333px; font-family: arial,helvetica,sans-serif; background-color: transparent; font-style: normal;"><span></span><br><span></span></div><div style="color: rgb(0, 0, 0); font-size: 13.3333px; font-family: arial,helvetica,sans-serif; background-color: transparent; font-style: normal;"><span>rule "</span><span>tasksInSameMaintenanceJobMustBeChained"<br>&nbsp;&nbsp; when<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $job: MaintenanceJob()<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $taskset : TaskSet( gapCount &gt; 0 )<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; from accumulate( $task : Task(jobId== $job.id),<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
 &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; init( TaskSet taskset = new TaskSet(); ),<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; action( taskset.addTask( $task ); ),<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; reverse( taskset.removeTask( $task ); ),<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; result( taskset ) );<br>&nbsp;&nbsp; then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; insertLogical(new IntConstraintOccurrence("</span><span><span></span><span>tasksInSameMaintenanceJobMustBeChained</span>",
 ConstraintType.NEGATIVE_HARD, </span><span>Importance.chainedPeriod * $taskset.getGapCount(), $job, $taskset));<br>end<br></span></div><div>&nbsp;<br>I see a difference in score but still not optimal and terminated on time limit reached.<br><br><span style="text-decoration: underline;"><span>1) Is this rule as good as it can be? Or am I creating some issue here?</span></span><br><br>A Task (planning entity) has 3 different planning variables.<br><span style="text-decoration: underline;">2) When I analyze the Trace logging I see that during the first steps the 3 variables&nbsp; are switched during moves, but then after a while only one of the 3 variables gets changed and the other variables of all tasks remain as they are.</span><br><br>Should I conclude something out of that?<br><br>This is my local search config:<br><br>&nbsp;&nbsp;&nbsp; &lt;localSearch&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;termination&gt;<br>&nbsp;&nbsp;&nbsp;
 &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;terminationCompositionStyle&gt;OR&lt;/terminationCompositionStyle&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;maximumSecondsSpend&gt;3600&lt;/maximumSecondsSpend&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;scoreAttained&gt;0hard/0soft&lt;/scoreAttained&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/termination&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;unionMoveSelector&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;changeMoveSelector&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;valueSelector&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;!-- **&nbsp; --&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
 &lt;planningVariableName&gt;role&lt;/planningVariableName&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/valueSelector&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/changeMoveSelector&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;changeMoveSelector&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;valueSelector&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- entity var technician:who will execute the task --&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;planningVariableName&gt;technician&lt;/planningVariableName&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/valueSelector&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
 &lt;/changeMoveSelector&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;changeMoveSelector&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;valueSelector&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- entity var period: when will the plane get maintenance --&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;planningVariableName&gt;period&lt;/planningVariableName&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/valueSelector&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/changeMoveSelector&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;swapMoveSelector&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/swapMoveSelector&gt;<br>&nbsp;&nbsp;&nbsp;
 &nbsp;&nbsp;&nbsp; &lt;/unionMoveSelector&gt;<br><br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;acceptor&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- 3 =&gt; small amount of planning entities in unit test --&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;planningEntityTabuSize&gt;3&lt;/planningEntityTabuSize&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/acceptor&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;forager&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;minimalAcceptedSelection&gt;1000&lt;/minimalAcceptedSelection&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/forager&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/localSearch&gt;<br><br>(**) entity var role: every maintenance job has one lead task (role == lead),
 all other tasks in that job must have role = member. The technician 
assigned to the lead task will file the maintenance report.<br>One of the constraints (checked in other rule) is that no technician should be lead-technician twice in a row on two sequential maintenance jobs.<br><br>Thanks in advance.<br><br>Michiel<br></div><div>-----------------<br>http://www.codessentials.com - Your essential software, for free!<br>Follow us at http://twitter.com/#!/Codessentials</div></div></body></html>