best rule for grouping planning entities?
by Michiel Vermandel
Hi,
I need to group a number of entities together and I'm not sure if my rule is optimal.
My planning entities represent maintenance tasks on airplanes.
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.
Every task has a duration depending on its type (checking engine takes longer than checking tires).
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).
Though, the smaller the better, at least all tasks should be sequential (without gaps between the tasks).
Dependencies on the tasks are availability of the plain, availability of the technicians...
(The rules beneath only check that the tasks are chained together, not (yet) that the time span is minimal => I thought to make a soft-constraint for that).
First I had this rule:
rule "tasksInSameMaintenanceJobMustBeChained"
when
$task : Task( $jobId: jobId )
not ( Task( jobId== $jobId, id != $task.id, ($task.startPeriodId-1) <= endPeriodId && ($task.endPeriodId+1) >= startPeriodId ) )
then // we have a gap!
insertLogical(new IntConstraintOccurrence("tasksInSameMaintenanceJobMustBeChained", ConstraintType.NEGATIVE_HARD, Importance.chainedPeriod, $jobId, $task));
end
After adding this rule I started struggling with what I believe is to be a score trap.
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.
So I rewrote the task to:
(I have now put all 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)
rule "tasksInSameMaintenanceJobMustBeChained"
when
$job: MaintenanceJob()
$taskset : TaskSet( gapCount > 0 )
from accumulate( $task : Task(jobId== $job.id),
init( TaskSet taskset = new TaskSet(); ),
action( taskset.addTask( $task ); ),
reverse( taskset.removeTask( $task ); ),
result( taskset ) );
then
insertLogical(new IntConstraintOccurrence("tasksInSameMaintenanceJobMustBeChained", ConstraintType.NEGATIVE_HARD, Importance.chainedPeriod * $taskset.getGapCount(), $job, $taskset));
end
I see a difference in score but still not optimal and terminated on time limit reached.
1) Is this rule as good as it can be? Or am I creating some issue here?
A Task (planning entity) has 3 different planning variables.
2) When I analyze the Trace logging I see that during the first steps the 3 variables 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.
Should I conclude something out of that?
This is my local search config:
<localSearch>
<termination>
<terminationCompositionStyle>OR</terminationCompositionStyle>
<maximumSecondsSpend>3600</maximumSecondsSpend>
<scoreAttained>0hard/0soft</scoreAttained>
</termination>
<unionMoveSelector>
<changeMoveSelector>
<valueSelector>
<!-- ** -->
<planningVariableName>role</planningVariableName>
</valueSelector>
</changeMoveSelector>
<changeMoveSelector>
<valueSelector>
<!-- entity var technician:who will execute the task -->
<planningVariableName>technician</planningVariableName>
</valueSelector>
</changeMoveSelector>
<changeMoveSelector>
<valueSelector>
<!-- entity var period: when will the plane get maintenance -->
<planningVariableName>period</planningVariableName>
</valueSelector>
</changeMoveSelector>
<swapMoveSelector>
</swapMoveSelector>
</unionMoveSelector>
<acceptor>
<!-- 3 => small amount of planning entities in unit test -->
<planningEntityTabuSize>3</planningEntityTabuSize>
</acceptor>
<forager>
<minimalAcceptedSelection>1000</minimalAcceptedSelection>
</forager>
</localSearch>
(**) 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.
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.
Thanks in advance.
Michiel
-----------------
http://www.codessentials.com - Your essential software, for free!
Follow us at http://twitter.com/#!/Codessentials
13 years, 1 month
CustomSolverPhaseCommand throws The entity ... was never added to this ScoreDirector.
by Michiel Vermandel
Hi,
I am trying to use a CustomSolverPhaseCommand (SolutionInitializer) to analyze what happens if I start with a given configuration.
I get java.lang.IllegalArgumentException: The entity ({T= Inspect B747-XA2.I#0 [1->3] null null}) was never
added to this ScoreDirector.
If I keep the constructionHeuristic phase before the SolutionInitializer then it works, but if I remove the constructionHeuristic phase and thus start with my SolutionInitializerthen I get the exception.
I reduced my SolutionInitializer to a minmal but the issue remains.
What am I doing wrong?
This is my SolutionInitializer:
package planner.solution;
import org.drools.planner.core.phase.custom.CustomSolverPhaseCommand;
import org.drools.planner.core.score.Score;
import org.drools.planner.core.score.director.ScoreDirector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import planner.app.InspectionSchedule;
import planner.domain.Task;
public class SolutionInitializer implements CustomSolverPhaseCommand {
private Logger logger = LoggerFactory.getLogger(this.getClass());
public void changeWorkingSolution(ScoreDirector scoreDirector) {
InspectionSchedule schedule = (InspectionSchedule) scoreDirector.getWorkingSolution();
Task task = schedule.getTasks().get(0);
scoreDirector.beforeVariableChanged(task, "period");
task.setPeriod(schedule.getPeriods().get(0));
scoreDirector.afterVariableChanged(task, "period");
score = scoreDirector.calculateScore();
logger.debug("Score after custom: " + score);
}
}
planning configuration:
<?xml version="1.0" encoding="UTF-8"?>
<solver>
<environmentMode>DEBUG</environmentMode>
<!-- Domain model configuration -->
<solutionClass>be.axi.planner.app.InspectionSchedule</solutionClass>
<planningEntityClass>be.axi.planner.domain.Task</planningEntityClass>
<!-- Score configuration -->
<scoreDirectorFactory>
<scoreDefinitionType>HARD_AND_SOFT</scoreDefinitionType>
<scoreDrl>/inspectionRules.drl</scoreDrl>
</scoreDirectorFactory>
<customSolverPhase>
<customSolverPhaseCommandClass>be.axi.planner.solution.SolutionInitializer</customSolverPhaseCommandClass>
</customSolverPhase>
<localSearch>
<termination>
<terminationCompositionStyle>OR</terminationCompositionStyle>
<maximumSecondsSpend>3600</maximumSecondsSpend>
<scoreAttained>0hard/0soft</scoreAttained>
</termination>
<unionMoveSelector>
<changeMoveSelector>
<valueSelector>
<planningVariableName>type</planningVariableName>
</valueSelector>
</changeMoveSelector>
<changeMoveSelector>
<valueSelector>
<planningVariableName>spector</planningVariableName>
</valueSelector>
</changeMoveSelector>
<changeMoveSelector>
<valueSelector>
<planningVariableName>period</planningVariableName>
</valueSelector>
</changeMoveSelector>
</unionMoveSelector>
<acceptor>
<planningEntityTabuSize>7</planningEntityTabuSize>
</acceptor>
<forager>
<minimalAcceptedSelection>1000</minimalAcceptedSelection>
</forager>
</localSearch>
</solver>
Stack trace:
java.lang.IllegalArgumentException: The entity ({T= Inspect B747-XA2.I#0 [1->3] null null}) was never added to this ScoreDirector.
at org.drools.planner.core.score.director.drools.DroolsScoreDirector.afterVariableChanged(DroolsScoreDirector.java:125)
at planner.solution.SolutionInitializer.changeWorkingSolution(SolutionInitializer2.java:24)
at org.drools.planner.core.phase.custom.DefaultCustomSolverPhase.solve(DefaultCustomSolverPhase.java:58)
at org.drools.planner.core.solver.DefaultSolver.runSolverPhases(DefaultSolver.java:190)
at org.drools.planner.core.solver.DefaultSolver.solve(DefaultSolver.java:155)
at planner.app.InspectionSchedule.solve(InspectionSchedule.java:192)
at planner.testcore.AbstractPlanningTestClass.solve(AbstractPlanningTestClass.java:288)
at planner.testcore.AbstractPlanningTestClass.solve(AbstractPlanningTestClass.java:298)
at planner.testcore.AbstractPlanningTestClass.solve(AbstractPlanningTestClass.java:315)
at planner.TaskGroupingTest.communitySuccess02(TaskGroupingTest.java:289)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Thanks,
Michiel
-----------------
http://www.codessentials.com - Your essential software, for free!
Follow us at http://twitter.com/#!/Codessentials
13 years, 1 month
Constraints over Lists
by Phani Saripalli
Hi, I have a query reg. writing constraints over lists.
Precisely heres what I m doing
//Imports
import java.util.List;
import java.util.Set;
import java.util.Arrays;
import java.util.ArrayList;
//My methods - functions
function boolean isDefined(Object ob) {
return ob != null;
}
function boolean neqq(List l1, List l2) {
return l1 != l2;
}
//List declaration
declare Project
@typesafe (false)
list1 : List
list2 : List
end
//Initial declaration rule
rule " Config rule "
agenda-group "Group Config"
dialect "mvel"
no-loop true
lock-on-active true
when
P : Project()
then
modify(P) {
list1 = new java.util.ArrayList(java.util.Arrays.asList(10, 15, 20, 25)),
list2 = new java.util.ArrayList(java.util.Arrays.asList(11, 2, 3, 4, 5,
10, 9, 8, 7))
};
update(P);
end
//Rule-constraint
rule "listEq1"
agenda-group "Group 2"
dialect "mvel"
no-loop true
lock-on-active true
when
P : Project( isDefined(P.list1)
&& neqq(P.list1, new java.util.ArrayList(java.util.Arrays.asList(1, 2, 3)))
)
then
System.out.println("Lists are not equal - 1");
end
//Rule - constraint 2
rule "listEq2"
agenda-group "Group 2"
dialect "mvel"
no-loop true
lock-on-active true
when
P : Project( isDefined(P.list1) && isDefined(P.list2)
&& neqq(P.list1, P.list2)
)
then
System.out.println("Lists are not equal - 2");
end
******************
If I remove the rule "listEq1", everything works fine, other it raises
several exceptions like
- Exception executing consequence for rule " Config rule "
- cannot invoke method asList
- cannot invoke method neqq
Can anyone tell me whats going on here, whats the reason for this.
Many thanks :)
Phani
--
View this message in context: http://drools.46999.n3.nabble.com/Constraints-over-Lists-tp4021715.html
Sent from the Drools: User forum mailing list archive at Nabble.com.
13 years, 1 month
Stateful session marshaling on drools server
by Ramgopal Tanikella
Hi,
I am using Drools Server 5.4.0.Final as a web application deployed on JBoss AS 7.1.1.Final. I have a stateful session configured on the server, and I am able to remotely execute against it inserting facts, retracting facts, firing rules, etc. How do I marshal/unmarshal a stateful session that is on the drools server?
Thanks,
Ramgopal Tanikella
________________________________
NOTICE TO RECIPIENT: THIS E-MAIL (INCLUDING ANY ATTACHMENTS) IS MEANT FOR ONLY THE INTENDED RECIPIENT OF THE TRANSMISSION, MAY CONTAIN CONFIDENTIAL INFORMATION, AND IS PROTECTED BY LAW. IF YOU RECEIVED THIS E-MAIL IN ERROR, PLEASE IMMEDIATELY NOTIFY THE SENDER OF THE ERROR BY RETURN E-MAIL, DELETE THIS COMMUNICATION AND SHRED ANY ATTACHMENTS. UNAUTHORIZED REVIEW, USE, DISSEMINATION, DISTRIBUTION, COPYING OR TAKING OF ANY ACTION BASED ON THIS COMMUNICATION IS STRICTLY PROHIBITED.
13 years, 1 month
Planner - NurseRostering: MaxWorkingWeekendsInFourWeeks
by John Poole
The parameters for MaxWorkingWeekendsInFourWeeks is in some of the
input files for the NurseRostering example, but it doesn't seem to be
the rules(drl) file.
Is it implemented elsewhere? I've tried doing is like this, but it
doesn't work as a HARD constraint. I'm running it as SOFT now, but it
would nice to compare it to a better version.
//Rules for workingweekends
rule "insertWorkingWeekends"
when
MinMaxContractLine(contractLineType ==
ContractLineType.TOTAL_WORKING_WEEKENDS_IN_FOUR_WEEKS, enabled ==
true,
$contract : contract)
$employee : Employee(contract == $contract)
ShiftAssignment(employee == $employee, $shiftDateDayIndex :
shiftDate.dayIndex, weekend == true)
then
insertLogical(new WorkingWeekend($employee, $shiftDateDayIndex/7));
end
// Maximum working weekends in four weeks
rule "insertWorkingWeekendsInFourWeeks"
// salience 1 // Do these rules first (optional, for performance)
when
MinMaxContractLine(contractLineType ==
ContractLineType.TOTAL_WORKING_WEEKENDS_IN_FOUR_WEEKS, enabled ==
true,
$contract : contract)
$employee : Employee(contract == $contract)
WorkingWeekend(employee == $employee, $week: week)
$workingWeekendTotal : Number() from accumulate(
$workingWeekend : WorkingWeekend(employee == $employee,
week >= $week, week-$week < 3 ),
count($workingWeekend)
)
then
insertLogical(new WorkingWeekendTotalFourWeeks($employee,
$workingWeekendTotal.intValue(), $week));
end
// Maximum working weekends in four weeks
rule "maxWorkingWeekendsInFourWeeks"
when
$contractLine : MinMaxContractLine(
contractLineType ==
ContractLineType.TOTAL_WORKING_WEEKENDS_IN_FOUR_WEEKS, maximumEnabled
== true,
$contract : contract, $maximumValue : maximumValue
)
$employee : Employee(contract == $contract)
WorkingWeekendTotalFourWeeks(employeeContract == $contract,
total > $maximumValue,
employee==$employee, $total : total, $week : week)
then
insertLogical(new
IntConstraintOccurrence("maxWorkingWeekendsInFourWeeks",
ConstraintType.NEGATIVE_SOFT,
($total - $maximumValue) * $contractLine.getMaximumWeight(),
$employee, $week));
end
13 years, 1 month
Re: [rules-users] DSL Enumerations
by GPatel@tsys.com
I wish the entire rule editing context (all the sentences and user entries) was made available to enumeration providers, then this would have been possible.
----- Original Message -----
From: rjr201 [rich.j.riley(a)gmail.com]
Sent: 01/22/2013 06:59 AM PST
To: rules-users(a)lists.jboss.org
Subject: Re: [rules-users] DSL Enumerations
Ok. Thanks for letting me know.
--
View this message in context: http://drools.46999.n3.nabble.com/DSL-Enumerations-tp4021696p4021727.html
Sent from the Drools: User forum mailing list archive at Nabble.com.
_______________________________________________
rules-users mailing list
rules-users(a)lists.jboss.org
https://lists.jboss.org/mailman/listinfo/rules-users
-----------------------------------------
The information contained in this communication (including any
attachments hereto) is confidential and is intended solely for the
personal and confidential use of the individual or entity to whom
it is addressed. If the reader of this message is not the intended
recipient or an agent responsible for delivering it to the intended
recipient, you are hereby notified that you have received this
communication in error and that any review, dissemination, copying,
or unauthorized use of this information, or the taking of any
action in reliance on the contents of this information is strictly
prohibited. If you have received this communication in error,
please notify us immediately by e-mail, and delete the original
message. Thank you
13 years, 1 month
how to analyse planner TRACE logging
by Michiel Vermandel
Hi,
I'm trying to find an issue that I expect to be a score trap.
As Geoffrey pointed out I enabled TRACE logging, which produces a rather big file.
Is there documentation on how to interpret the content?
There are some things that I do not understand:
1) I see sometimes this type of logging:
TRACE main org.drools.planner.core.localsearch.decider.DefaultDecider - Move index (249), score (-484hard/0soft), accepted (true) for move ({T= Inspect B747-AX.I#0 [P1] Kristof IV} <=> {T= Inspect A311-DX.I#1 [P1] Gerald IV}).
What does the <=> mean in this logging? What does the move actually do in this case?
2) TRACE main org.drools.planner.core.localsearch.decider.DefaultDecider - Move index (273), score (-5562hard/0soft), accepted (true) for move ({T= Inspect B747-AX.I#0 [P3] Kristof IV} => (P9) ).
This line indicates that the move is accepted. Is a move accepted before validating the rules or after? And in the same way does the score (-5562hard/0soft) indicate the score before or after the validation of the rules?
Can someone give me some directions, please?
Thanks,
Michiel
-----------------
http://www.codessentials.com - Your essential software, for free!
Follow us at http://twitter.com/#!/Codessentials
13 years, 1 month
[Bug] cannot invoke method: asList
by Wolfgang Laun
Below is a self-contained DRL which, when run with 5.5.0, throws an
exception "cannot invoke method asList". Remarkably, this only happens
when a second Project fact is inserted. (Haven't I heard this before?)
-W
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
declare Project
@typesafe (false)
list1 : List
list2 : List
end
rule kickoff
salience 999999
when
then
insert( new Project() );
insert( new Project() ); // necessary to trigger the exception
end
rule " Config rule "
dialect "mvel"
no-loop true
when
P : Project()
then
modify(P) {
list1 = Arrays.asList(10, 15, 20, 25),
list2 = Arrays.asList(11, 2, 3, 4, 5, 10, 9, 8, 7)
};
end
Exception in thread "main" Exception executing consequence for rule "
Config rule " in express: java.lang.RuntimeException: cannot construct
object
at org.drools.runtime.rule.impl.DefaultConsequenceExceptionHandler.handleException(DefaultConsequenceExceptionHandler.java:39)
at org.drools.common.DefaultAgenda.fireActivation(DefaultAgenda.java:1297)
at org.drools.common.DefaultAgenda.fireNextItem(DefaultAgenda.java:1221)
at org.drools.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1456)
at org.drools.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:710)
at org.drools.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:674)
at org.drools.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:230)
at express.Main.execute(Main.java:77)
at express.Main.main(Main.java:110)
Caused by: java.lang.RuntimeException: cannot construct object
at org.mvel2.optimizers.impl.refl.nodes.ConstructorAccessor.getValue(ConstructorAccessor.java:63)
at org.mvel2.ast.NewObjectNode.getReducedValueAccelerated(NewObjectNode.java:233)
at org.mvel2.compiler.ExecutableAccessor.getValue(ExecutableAccessor.java:42)
at org.mvel2.ast.WithNode$ParmValuePair.eval(WithNode.java:281)
at org.mvel2.ast.WithNode.getReducedValueAccelerated(WithNode.java:67)
at org.mvel2.ast.InterceptorWrapper.getReducedValueAccelerated(InterceptorWrapper.java:40)
at org.mvel2.MVELRuntime.execute(MVELRuntime.java:85)
at org.mvel2.compiler.CompiledExpression.getDirectValue(CompiledExpression.java:123)
at org.mvel2.compiler.CompiledExpression.getValue(CompiledExpression.java:119)
at org.mvel2.MVEL.executeExpression(MVEL.java:930)
at org.drools.base.mvel.MVELConsequence.evaluate(MVELConsequence.java:104)
at org.drools.common.DefaultAgenda.fireActivation(DefaultAgenda.java:1287)
... 7 more
Caused by: java.lang.RuntimeException: cannot invoke method: asList
at org.mvel2.optimizers.impl.refl.nodes.MethodAccessor.getValue(MethodAccessor.java:63)
at org.mvel2.optimizers.impl.refl.nodes.VariableAccessor.getValue(VariableAccessor.java:37)
at org.mvel2.ast.ASTNode.getReducedValueAccelerated(ASTNode.java:108)
at org.mvel2.compiler.ExecutableAccessor.getValue(ExecutableAccessor.java:42)
at org.mvel2.optimizers.impl.refl.nodes.ConstructorAccessor.executeAll(ConstructorAccessor.java:76)
at org.mvel2.optimizers.impl.refl.nodes.ConstructorAccessor.getValue(ConstructorAccessor.java:43)
... 18 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: 4
at org.mvel2.optimizers.impl.refl.nodes.MethodAccessor.executeAll(MethodAccessor.java:149)
at org.mvel2.optimizers.impl.refl.nodes.MethodAccessor.getValue(MethodAccessor.java:48)
... 23 more
13 years, 1 month