[rules-users] Re: Drools-solver performance optimizations?

Geoffrey De Smet ge0ffrey.spam at gmail.com
Sat Feb 14 04:12:15 EST 2009


I've worked at Kaho and I know Peter De Meester, his custom algorithms 
do pretty well :)

I am really interested in how the different components measure up in speed:
- calculating a single score (no doubt drools-solver will lose this one 
due to the warmup time of drools)
- calculating 10.000 scores after calculating 10.000 scores to give 
hotspot compiling some time to warm up. Each scores changes into the 
next by a move (to allow score delta calculation).
- number of calculated scores per second and only start measuring after 
100 seconds
- average number of moves per minute
- average number of moves per step
- average number of steps per minute
You'd do me a grand favor by publishing any results on this mailing 
list, so we can find out where and how drools-solver needs improving.
Patches on drools-solver are always welcome of course too.

One thing that drools-solver currently lacks is build-in support for 
rotating (phasing) through different local search solvers (first 
simulated annealing, then tabu search, then great deluge, then start 
over). It shouldn't be hard to implement that on top of drools-solver 
for now.
Also drools-solver currently only utilizes one CPU (it's single 
threaded). Multi-thread support is coming. So you might want to take a 
look at how the number of CPU's affect the other algorithms.

Anyway, first clean up your rules, tweak relativeSelection, use a 
starting solution initializer, tweak other configuration, ...: that will 
make a big difference. It's a game of perseverance - may the best 
algorithm win :)

With kind regards,
Geoffrey De Smet


Wim Vancroonenburg schreef:
> Thanks to everybody for the tips. I will see what I can do with them to 
> squeeze out that last bit of performance.
> 
> To Geoffrey:
> 
> I just wanted to let you know that I'm the thesis student from KAHOSL 
> that is using Drools Solver for the Patient Admission 
> Scheduling-problem. The performance of Drools Solver isn't bad, but I'm 
> trying to match my promotor's code. His code is substantialy faster at 
> the moment (a hyperheuristic implementation). So I'm trying to squeeze 
> out every bit of performance. Thanks for the tips and the quick response 
> by the way.
> 
> Sincerely,
> 
> Wim Vancroonenburg.
> 
> 
> ----- Original Message ----- From: "Geoffrey De Smet" 
> <ge0ffrey.spam at gmail.com>
> Newsgroups: gmane.comp.java.drools.user
> To: <rules-users at lists.jboss.org>
> Sent: Friday, February 13, 2009 3:32 PM
> Subject: Re: Drools-solver performance optimizations?
> 
> 
>> Take a look at some of the tricks in the ITC2007 examination example:
>>
>> - <relativeSelection>0.002</relativeSelection> Real-world problems are 
>> so big that you can't evaluate all moves for every step. You need to 
>> take a random percentage (for example 0.2%) of all moves to evaluate.
>> If you aren't using this, use it and you should see a big difference.
>> Once you're a 100% confident in your score function, use the 
>> benchmarker to determine the perfect relativeSelection.
>>
>> - I calculate a TopicConflict list before starting the solver and use 
>> it in my score drl, because none of the move change the result of that 
>> calculation - and it's used a lot.
>>
>> - avoid backwards chaining functions when possible, like accumulate, 
>> exists, collect, ... Forward chaining = free score delta calculation.
>>
>> - Use the most limiting facts first, so
>>   $room : Room(sexRestriction == Sex.Dependent && capacity > 1);
>> before
>>   $n : Night();
>>
>>
>> Most of your rules look good. I do recommend turning them off one by 
>> one to see if none outclasses all others in CPU consumption, so you 
>> know which one to put your time into.
>>
>> I would rewrite the patientsToBeAssignedToRoomsOfAppropriateSex as such
>>
>> rule "patientsToBeAssignedToRoomsOfAppropriateSex"
>>         when
>>                 $room : Room(sexRestriction == Sex.Dependent && 
>> capacity > 1);
>>                 ps1 : PatientStay(bed.room == $room, n : night, 
>> $leftId : id, g : patient.admission.sex)
>>                 ps2 : PatientStay(bed.room == $room, night == $n, 
>> patient.admission.sex != $g, id > $leftId)
>>         then
>>                 insertLogical(new 
>> IntConstraintOccurrence("patientsToBeAssignedToRoomsOfAppropriateSex",ConstraintType.NEGATIVE_HARD, 
>> 50, $ps1, $ps2));
>> end
>>
>> I do the id thing because otherwise it would match twice, once for A 
>> and B and once for B and A
>>
>> PS: be carefull with "PatientStay(bed.room == ...), IIRC it gets 
>> MVEL'ed (= a bit performance loss) or flattening is a problem because 
>> the move only does an update(PatientStay) (=> score gets corrupted on 
>> second calculation)
>> PatientStay(room == ...) with PatiantStay.getRoom(){return 
>> getBed().getRoom()) isn't dangerous
>> Mark or Edson could probably answer this question.
>>
>>
>> With kind regards,
>> Geoffrey De Smet
>>
>>
>> Wim Vancroonenburg schreef:
>>> Hi,
>>>
>>> I'm a student currently evaluating Drools Solver for my dissertation. 
>>> I am currently trying to solve an optimization problem with two 
>>> different solvers (one of which is Drools Solver) and I am comparing 
>>> the results with earlier obtained results from literature. However I 
>>> am having some troubles with the performance of Drools Solver, and I 
>>> was hoping if someone could look at my rules to see if they could be 
>>> tuned:
>>>
>>> rule "patientsToBeAssignedToRoomsOfAppropriateSex"
>>>         when
>>>                 $n : Night();
>>>                 $room : Room(sexRestriction == Sex.Dependent && 
>>> capacity  > 1);
>>>                 $genders : ArrayList(size>1) from collect( 
>>> PatientStay(bed.room == $room, night == $n) );
>>
>>>                 exists PatientStay(bed.room == $room, night == $n, $a 
>>> : admission, 
>>> eval(((PatientStay)$genders.get(0)).getAdmission().getPatient().getSex() 
>>> != $a.getPatient().getSex()));
>>>         then
>>>                 insertLogical(new 
>>> IntConstraintOccurrence("patientsToBeAssignedToRoomsOfAppropriateSex",ConstraintType.NEGATIVE_HARD,50,$room,$n)); 
>>>
>>> end
>>>
>>> rule "hasRequiredRoomProperties"
>>>         when
>>>                 $pr : RequiredRoomPropertiesConstraint($a : 
>>> admission, $r : room, $w : weight );
>>>                 $ps : PatientStay(admission == $a, bed.room == $r);
>>>         then
>>>                 insertLogical(new 
>>> IntConstraintOccurrence("hasPreferredRoomProperties",ConstraintType.NEGATIVE_SOFT,50*$w,$ps)); 
>>>
>>> end
>>>
>>> rule "unplannedTransfers"
>>>         when
>>>                 $ps : PatientStay($a : admission, $b : bed, $n : night);
>>>                 $ps2 : PatientStay(admission == $a, bed != $b, $n2 : 
>>> night,eval($n.getIndex()+1 == $n2.getIndex()));
>>>         then
>>>                 insertLogical(new 
>>> IntConstraintOccurrence("unplannedTransfers",ConstraintType.NEGATIVE_SOFT,110,$ps,$ps2)); 
>>>
>>> end
>>>
>>> rule "hasPreferredRoomProperties"
>>>         when
>>>                 $pr : PreferredRoomPropertiesConstraint($a : 
>>> admission, $r : room, $w : weight );
>>>                 $ps : PatientStay(admission == $a, bed.room == $r);
>>>         then
>>>                 insertLogical(new 
>>> IntConstraintOccurrence("hasPreferredRoomProperties",ConstraintType.NEGATIVE_SOFT,20*$w,$ps)); 
>>>
>>> end
>>>
>>> rule "meetsRoomPreference"
>>>         when
>>>                 $mr : MeetsRoomPreferenceConstraint($a : admission, 
>>> $r : room);
>>>                 $ps : PatientStay(admission == $a, bed.room == $r);
>>>         then
>>>                 insertLogical(new 
>>> IntConstraintOccurrence("meetsRoomPreference",ConstraintType.NEGATIVE_SOFT,8,$ps)); 
>>>
>>> end
>>>
>>> rule "inGoodDepartment"
>>>         when
>>>                 $gd : GoodDepartmentConstraint($a : admission, $d : 
>>> department);
>>>                 $ps : PatientStay(admission == $a, $b : bed, 
>>> eval($b.getRoom().getDepartment().equals($d)));
>>>         then
>>>                 insertLogical(new 
>>> IntConstraintOccurrence("inGoodDepartment",ConstraintType.NEGATIVE_SOFT,10,$ps)); 
>>>
>>> end
>>>
>>> rule "inGoodRoom"
>>>         when
>>>                 $gr : GoodRoomConstraint($a : admission, $r : room, 
>>> $w : weight);
>>>                 $ps : PatientStay(admission == $a, bed.room == $r);
>>>         then
>>>                 insertLogical(new 
>>> IntConstraintOccurrence("inGoodRoom",ConstraintType.NEGATIVE_SOFT,10*$w,$ps)); 
>>> end
>>>
>>> rule "calcScore"
>>> salience -10
>>>         when
>>>                 $count : Number() from accumulate( 
>>> IntConstraintOccurrence($w : weight) ,
>>>
>>> sum($w) );
>>>         then
>>>                 scoreCalculator.setScore(-$count.doubleValue());
>>> end
>>>
>>> The classes with **Constraint in it are possible combinations that 
>>> cause a constraint to be violated, and are calculated and inserted at 
>>> initialization time (and are never changed). I know that the rule 
>>> "patientsToBeAssignedToRoomsOfAppropriateSex" is fairly complex, but 
>>> even when I remove it, the performance is not fantastic. Is there 
>>> anything else I can do to get better performance? I'm already using 
>>> JDK 1.6 and -server mode. Furthermore, all classes used here have 
>>> their default equals and hashCode methods, so they don't have an 
>>> impact on performance.
>>>
>>> Sincerely,
>>>
>>> Wim Vancroonenburg
>>>
>>>
>>> ------------------------------------------------------------------------
>>>
>>> _______________________________________________
>>> rules-users mailing list
>>> rules-users at lists.jboss.org
>>> https://lists.jboss.org/mailman/listinfo/rules-users
>>
>> _______________________________________________
>> rules-users mailing list
>> rules-users at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/rules-users
>>
> 
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-users
> 




More information about the rules-users mailing list