Drools Rules for Blocks World Example

insertnew Blocktable, , A; end The following rule looks for situations where it is possible to move a block with a few conditions: • Find a block block 1 that is on top of another block and is not itself supporting any other blocks • Find a second block block 2 that is not block 1 and is not itself supporting any other blocks • Find the block on top of 1 that is under block 2 and supporting block 1 • Make sure that no previous block with the name in the variable block 2 has already been on top of block on top of 2 and supporting block 1 If these conditions are met, we can remove the three matching facts and create facts for the new block positions and a new OldBlockState fact in working memory. Note that the fourth LHS matching pattern is prefixed with “not” so this matches if there are no objects in working memory that match this pattern: rule Set Block On: move block_1 to block_2 when fact1 : Blockblock_1 : name, on_top_of_1 : onTopOf = , supporting == fact2 : Blockblock_2 : name = block_1, on_top_of_2 : onTopOf = , supporting == fact3 : Blockname == on_top_of_1, on_top_of_3 : onTopOf, supporting == block_1 not OldBlockStatename == block_2, onTopOf == on_top_of_2, supporting == block_1 then System.out.println fact1 ; System.out.println fact2 ; System.out.println fact3 ; retractfact1; retractfact2; retractfact3; insertnew Blockblock_1, block_2, ; insertnew Blockblock_2, on_top_of_2, 86 block_1; insertnew OldBlockStateblock_2, on_top_of_2, ; insertnew Blockon_top_of_1, on_top_of_3, ; System.out.printlnMoving + block_1 + from + on_top_of_1 + to + block_2; end The next rule looks for opportunities to remove block 1 from block 2 if no other block is sitting on top of block 1 that is, block 1 is clear: rule Clear Block: remove block_1 from block_2 when fact1 : Blockblock_1 : name = table, on_top_of : onTopOf = table, supporting == fact2 : Blockblock_2 : name, on_top_of_2 : onTopOf, supporting == block_1 then System.out.println fact1 ; System.out.println fact2 ; retractfact1; retractfact2; insertnew Blockblock_1, table, ; insertnew Blockblock_2, on_top_of_2, ; insertnew Blocktable, , block_1; System.out.printlnClearing: remove + block_1 + from + on_top_of + to table; end The next rule checks to see if the current goal is satisfied in which case it halts the Drools engine: rule Halt on goal achieved salience 500 when Goalb1 : supportingBlock, b2 : supportedBlock Blockname == b1, supporting == b2 then 87 System.out.printlnDone; drools.halt; end The Java code in the next section can load and run these example rules.

5.4.3 Java Code for Blocks World Example

The example in this section introduces something new: modifying the default way that Drools chooses which rules to “fire” execute when more than one rule is eli- gible to fire. This is referred to as the “conflict resolution strategy” and this phrase dates back to the original OPS5 production system. Drools by default prefers rules that are instantiated by data that is newer in working memory. This is similar to depth first search. In the “blocks world” example in this section we will need to change the conflict resolution strategy to process rules in a first-in, first-out order which is similar to a breadth first search strategy. First, let us define the problem that we want to solve. Consider labeled blocks sitting on a table as seen in Figures 5.2 through 5.5. The Java code in this section is similar to what we already saw in Section 5.3 so we will just look at the differences here. To start with, in the utility method readRule we need to add a few lines of code to configure Drools to use a breadth-first instead of a depth-first reasoning strategy: private static RuleBase readRule throws Exception { Reader source = new InputStreamReader DroolsBlockWorld.class.getResourceAsStream BlockWorld.drl; PackageBuilder builder = new PackageBuilder; builder.addPackageFromDrl source ; Package pkg = builder.getPackage; Change the default conflict resolution strategy: RuleBaseConfiguration rbc = new RuleBaseConfiguration; rbc.setConflictResolvernew FifoConflictResolver; RuleBase ruleBase = RuleBaseFactory.newRuleBaserbc; ruleBase.addPackagepkg; 88 return ruleBase; } The Drools class F if oConf lictResolver is not so well named, but a first-in first- out FIFO strategy is like depth first search. The default conflict resolution strategy favors rules that are eligible to fire from data that has most recently changed. Since we have already seen the definition of the Java POJO classes used in the rules in Section 5.4.1 the only remaining Java code to look at is in the static main method: RuleBase ruleBase = readRule; WorkingMemory workingMemory = ruleBase.newStatefulSession; System.out.println\nInitial Working Memory:\n\n + workingMemory.toString; Just fire the first setup rule: workingMemory.fireAllRules1; IteratorFactHandle iter = workingMemory.iterateFactHandles; while iter.hasNext { System.out.printlniter.next; } System.out.println\n\n Before firing rules...; workingMemory.fireAllRules20; limit 20 cycles System.out.println\n\n After firing rules.; System.out.println\nFinal Working Memory:\n + workingMemory.toString; iter = workingMemory.iterateFactHandles; while iter.hasNext { System.out.printlniter.next; } For making rule debugging easier I wanted to run the first “start up” rule to define the initial problem facts in working memory, and then print working memory. That is why I called workingM emory.f ireAllRules 1 to ask the Drools rule engine to just fire one rule. In the last example we called workingM emory.f ireAllRules with no arguments so the rule engine runs forever as long as there are rules eligible to fire. After printing the facts in working memory I call the f ireAllRules 20 with a limit of 20 rule firings because blocks world problems can fail to terminate at least the simple rules that I have written for this example often failed to terminate when I was debugging this example. Limiting the number of rule firings is often a good idea. The output from this example with debug output removed is: Clearing: remove C from B to table 89