1 10 package com.hp.hpl.jena.reasoner.rulesys.impl; 11 12 import com.hp.hpl.jena.reasoner.*; 13 import com.hp.hpl.jena.reasoner.rulesys.*; 14 import com.hp.hpl.jena.graph.*; 15 import java.util.*; 16 17 import com.hp.hpl.jena.util.OneToManyMap; 18 import com.hp.hpl.jena.util.PrintUtil; 19 import com.hp.hpl.jena.util.iterator.*; 20 import com.hp.hpl.jena.vocabulary.RDF; 21 22 import org.apache.commons.logging.Log; 23 import org.apache.commons.logging.LogFactory; 24 25 32 public class FRuleEngine implements FRuleEngineI { 33 34 35 protected ForwardRuleInfGraphI infGraph; 36 37 38 protected List rules; 39 40 41 protected OneToManyMap clauseIndex; 42 43 44 protected HashSet predicatesUsed; 45 46 47 protected boolean wildcardRule; 48 49 50 protected boolean recordDerivations; 51 52 53 int nRulesTriggered = 0; 54 55 56 long nRulesFired = 0; 57 58 59 long nAxiomRulesFired = -1; 60 61 62 boolean processedAxioms = false; 63 64 protected static Log logger = LogFactory.getLog(FRuleEngine.class); 65 66 69 75 public FRuleEngine(ForwardRuleInfGraphI parent, List rules) { 76 infGraph = parent; 77 this.rules = rules; 78 } 79 80 86 public FRuleEngine(ForwardRuleInfGraphI parent) { 87 infGraph = parent; 88 } 89 90 93 101 public void init(boolean ignoreBrules, Finder inserts) { 102 if (clauseIndex == null) compile(rules, ignoreBrules); 103 findAndProcessAxioms(); 104 nAxiomRulesFired = nRulesFired; 105 logger.debug("Axioms fired " + nAxiomRulesFired + " rules"); 106 fastInit(inserts); 107 } 108 109 115 public void fastInit(Finder inserts) { 116 findAndProcessActions(); 117 BFRuleContext context = new BFRuleContext(infGraph); 119 if (wildcardRule) { 121 for (Iterator i = inserts.find(new TriplePattern(null, null, null)); i.hasNext(); ) { 122 context.addTriple((Triple)i.next()); 123 } 124 } else { 125 for (Iterator p = predicatesUsed.iterator(); p.hasNext(); ) { 126 Node predicate = (Node)p.next(); 127 for (Iterator i = inserts.find(new TriplePattern(null, predicate, null)); i.hasNext(); ) { 128 context.addTriple((Triple)i.next()); 129 } 130 } 131 } 132 addSet(context); 134 } 135 136 140 public synchronized void add(Triple t) { 141 BFRuleContext context = new BFRuleContext(infGraph); 142 context.addTriple(t); 143 addSet(context); 144 } 145 146 151 public synchronized boolean delete(Triple t) { 152 return false; 154 } 155 156 160 public long getNRulesFired() { 161 return nRulesFired; 162 } 163 164 168 public boolean shouldTrace() { 169 return true; 171 } 172 173 176 public void setDerivationLogging(boolean recordDerivations) { 177 this.recordDerivations = recordDerivations; 178 } 179 180 184 public Object getRuleStore() { 185 return new RuleStore(clauseIndex, predicatesUsed, wildcardRule); 186 } 187 188 191 public void setRuleStore(Object ruleStore) { 192 RuleStore rs = (RuleStore)ruleStore; 193 clauseIndex = rs.clauseIndex; 194 predicatesUsed = rs.predicatesUsed; 195 wildcardRule = rs.wildcardRule; 196 } 197 198 201 209 public void addSet(BFRuleContext context) { 210 Triple t; 211 while ((t = context.getNextTriple()) != null) { 212 if (infGraph.shouldTrace()) { 213 logger.info("Processing: " + PrintUtil.print(t)); 214 } 215 HashSet firedRules = new HashSet(); 217 Iterator i1 = clauseIndex.getAll(t.getPredicate()); 218 Iterator i2 = clauseIndex.getAll(Node.ANY); 219 Iterator i = new ConcatenatedIterator(i1, i2); 220 while (i.hasNext()) { 221 ClausePointer cp = (ClausePointer) i.next(); 222 if (firedRules.contains(cp.rule)) continue; 223 context.resetEnv(); 224 TriplePattern trigger = (TriplePattern) cp.rule.getBodyElement(cp.index); 225 if (match(trigger, t, context.getEnvStack())) { 226 nRulesTriggered++; 227 context.setRule(cp.rule); 228 if (matchRuleBody(cp.index, context)) { 229 firedRules.add(cp.rule); 230 nRulesFired++; 231 } 232 } 233 } 234 } 235 } 236 237 243 public void compile(List rules, boolean ignoreBrules) { 244 clauseIndex = new OneToManyMap(); 245 predicatesUsed = new HashSet(); 246 wildcardRule = false; 247 248 for (Iterator i = rules.iterator(); i.hasNext(); ) { 249 Rule r = (Rule)i.next(); 250 if (ignoreBrules && r.isBackward()) continue; 251 Object [] body = r.getBody(); 252 for (int j = 0; j < body.length; j++) { 253 if (body[j] instanceof TriplePattern) { 254 Node predicate = ((TriplePattern) body[j]).getPredicate(); 255 ClausePointer cp = new ClausePointer(r, j); 256 if (predicate.isVariable()) { 257 clauseIndex.put(Node.ANY, cp); 258 wildcardRule = true; 259 } else { 260 clauseIndex.put(predicate, cp); 261 if (! wildcardRule) { 262 predicatesUsed.add(predicate); 263 } 264 } 265 } 266 } 267 } 268 269 if (wildcardRule) predicatesUsed = null; 270 } 271 272 275 protected void findAndProcessAxioms() { 276 BFRuleContext context = new BFRuleContext(infGraph); 277 for (Iterator i = rules.iterator(); i.hasNext(); ) { 278 Rule r = (Rule)i.next(); 279 if (r.bodyLength() == 0) { 280 for (int j = 0; j < r.headLength(); j++) { 282 Object head = r.getHeadElement(j); 283 if (head instanceof TriplePattern) { 284 TriplePattern h = (TriplePattern) head; 285 Triple t = new Triple(h.getSubject(), h.getPredicate(), h.getObject()); 286 context.addTriple(t); 287 infGraph.getDeductionsGraph().add(t); 288 } 289 } 290 } 291 } 292 addSet(context); 293 processedAxioms = true; 294 } 295 296 299 protected void findAndProcessActions() { 300 BFRuleContext context = new BFRuleContext(infGraph); 301 for (Iterator i = rules.iterator(); i.hasNext(); ) { 302 Rule r = (Rule)i.next(); 303 if (r.bodyLength() == 0) { 304 for (int j = 0; j < r.headLength(); j++) { 306 Object head = r.getHeadElement(j); 307 if (head instanceof Functor) { 308 Functor f = (Functor)head; 309 Builtin imp = f.getImplementor(); 310 if (imp != null) { 311 context.setRule(r); 312 imp.headAction(f.getArgs(), f.getArgLength(), context); 313 } else { 314 throw new ReasonerException("Invoking undefined Functor " + f.getName() +" in " + r.toShortString()); 315 } 316 } 317 } 318 } 319 } 320 } 321 322 329 private boolean matchRuleBody(int trigger, BFRuleContext context) { 330 Rule rule = context.getRule(); 331 Object [] body = rule.getBody(); 333 int len = body.length; 334 ArrayList clauses = new ArrayList(len-1); 335 336 if (len <= 1) { 337 } else if (len == 2) { 339 Object clause = body[trigger == 0 ? 1 : 0]; 341 if (clause instanceof TriplePattern) { 342 clauses.add(clause); 343 } 344 } else { 345 int bestscore = 0; 347 int best = -1; 348 for (int i = 0; i < len; i++) { 349 if (i == trigger) continue; BindingStack env = context.getEnvStack(); 351 if (body[i] instanceof TriplePattern) { 352 TriplePattern clause = (TriplePattern) body[i]; 353 int score = scoreNodeBoundness(clause.getSubject(), env) * 3 + 354 scoreNodeBoundness(clause.getPredicate(), env) * 2 + 355 scoreNodeBoundness(clause.getObject(), env) * 3; 356 if (score > bestscore) { 357 bestscore = score; 358 best = i; 359 } 360 } 361 } 362 363 for (int i = 0; i < len; i++) { 364 if (i == trigger || i == best) continue; 365 if (body[i] instanceof TriplePattern) { 366 clauses.add(body[i]); 367 } 368 } 369 if (best != -1) clauses.add(body[best]); 370 } 371 372 boolean matched = matchClauseList(clauses, context); 374 if (matched) { 375 context.flushPending(); 378 } 379 return matched; 380 } 381 382 389 private boolean matchClauseList(List clauses, BFRuleContext context) { 390 Rule rule = context.getRule(); 391 BindingStack env = context.getEnvStack(); 392 int index = clauses.size() - 1; 393 if (index == -1) { 394 for (int i = 0; i < rule.bodyLength(); i++) { 396 Object clause = rule.getBodyElement(i); 397 if (clause instanceof Functor) { 398 if (!((Functor)clause).evalAsBodyClause(context)) { 400 return false; } 402 } 403 } 404 if (infGraph.shouldTrace()) { 406 logger.info("Fired rule: " + rule.toShortString() + " = " + rule.instantiate(env)); 407 } 408 List matchList = null; 409 if (recordDerivations) { 410 matchList = new ArrayList(rule.bodyLength()); 412 for (int i = 0; i < rule.bodyLength(); i++) { 413 Object clause = rule.getBodyElement(i); 414 if (clause instanceof TriplePattern) { 415 matchList.add(env.instantiate((TriplePattern)clause)); 416 } 417 } 418 } 419 for (int i = 0; i < rule.headLength(); i++) { 420 Object hClause = rule.getHeadElement(i); 421 if (hClause instanceof TriplePattern) { 422 Triple t = env.instantiate((TriplePattern) hClause); 423 if (!t.getSubject().isLiteral()) { 424 if ( ! context.contains(t) ) { 428 context.add(t); 429 if (recordDerivations) { 430 infGraph.logDerivation(t, new RuleDerivation(rule, t, matchList, infGraph)); 431 } 432 } 433 } 434 } else if (hClause instanceof Functor) { 435 Functor f = (Functor)hClause; 436 Builtin imp = f.getImplementor(); 437 if (imp != null) { 438 imp.headAction(f.getBoundArgs(env), f.getArgLength(), context); 439 } else { 440 throw new ReasonerException("Invoking undefined Functor " + f.getName() +" in " + rule.toShortString()); 441 } 442 } else if (hClause instanceof Rule) { 443 Rule r = (Rule)hClause; 444 if (r.isBackward()) { 445 infGraph.addBRule(r.instantiate(env)); 446 } else { 447 throw new ReasonerException("Found non-backward subrule : " + r); 448 } 449 } 450 } 451 return true; 452 } 453 ArrayList clausesCopy = (ArrayList)((ArrayList)clauses).clone(); 455 TriplePattern clause = (TriplePattern) clausesCopy.remove(index); 456 Node objPattern = env.getBinding(clause.getObject()); 457 if (Functor.isFunctor(objPattern)) { 458 objPattern = null; 460 } 461 Iterator i = infGraph.findDataMatches( 462 env.getBinding(clause.getSubject()), 463 env.getBinding(clause.getPredicate()), 464 env.getBinding(objPattern)); 465 boolean foundMatch = false; 466 while (i.hasNext()) { 467 Triple t = (Triple) i.next(); 468 env.push(); 470 if (match(clause.getPredicate(), t.getPredicate(), env) 471 && match(clause.getObject(), t.getObject(), env) 472 && match(clause.getSubject(), t.getSubject(), env)) { 473 foundMatch |= matchClauseList(clausesCopy, context); 474 } 475 env.unwind(); 476 } 477 return foundMatch; 478 } 479 480 486 public static int scoreNodeBoundness(Node n, BindingEnvironment env) { 487 if (n instanceof Node_ANY) { 488 return 0; 489 } else if (n instanceof Node_RuleVariable) { 490 Node val = env.getGroundVersion(n); 491 if (val == null) { 492 return 1; 493 } else if (val.equals(RDF.type.asNode())) { 494 return 2; 495 } else { 496 return 3; 497 } 498 } else { 499 return 3; 500 } 501 } 502 503 520 526 public static boolean match(TriplePattern pattern, Triple triple, BindingStack env) { 527 env.push(); 528 boolean matchOK = match(pattern.getPredicate(), triple.getPredicate(), env) 529 && match(pattern.getObject(), triple.getObject(), env) 530 && match(pattern.getSubject(), triple.getSubject(), env); 531 if (matchOK) { 532 env.commit(); 533 return true; 534 } else { 535 env.unwind(); 536 return false; 537 } 538 } 539 540 546 public static boolean match(Node pattern, Node node, BindingStack env) { 547 if (pattern instanceof Node_RuleVariable) { 548 int index = ((Node_RuleVariable)pattern).getIndex(); 549 return env.bind(index, node); 550 } else if (pattern instanceof Node_ANY) { 551 return true; 552 } else if (Functor.isFunctor(pattern)) { 553 if (!Functor.isFunctor(node)) return false; 554 Functor patternF = (Functor) pattern.getLiteral().getValue(); 555 Functor nodeF = (Functor) node.getLiteral().getValue(); 556 if (!patternF.getName().equals(nodeF.getName())) return false; 557 Node[] patternArgs = patternF.getArgs(); 558 Node[] nodeArgs = nodeF.getArgs(); 559 if (patternArgs.length != nodeArgs.length) return false; 563 env.push(); 565 boolean matchOK = true; 566 for (int i = 0; i < patternArgs.length; i++) { 567 if (!match(patternArgs[i], nodeArgs[i], env)) { 568 matchOK = false; 569 break; 570 } 571 } 572 if (matchOK) { 573 env.commit(); 574 return true; 575 } else { 576 env.unwind(); 577 return false; 578 } 579 } else { 581 return pattern.sameValueAs(node); 582 } 583 } 584 585 588 593 protected static class ClausePointer { 594 595 596 protected Rule rule; 597 598 599 protected int index; 600 601 602 ClausePointer(Rule rule, int index) { 603 this.rule = rule; 604 this.index = index; 605 } 606 607 608 TriplePattern getClause() { 609 return (TriplePattern)rule.getBodyElement(index); 610 } 611 } 612 613 616 public static class RuleStore { 617 618 619 protected OneToManyMap clauseIndex; 620 621 622 protected HashSet predicatesUsed; 623 624 625 protected boolean wildcardRule; 626 627 628 RuleStore(OneToManyMap clauseIndex, HashSet predicatesUsed, boolean wildcardRule) { 629 this.clauseIndex = clauseIndex; 630 this.predicatesUsed = predicatesUsed; 631 this.wildcardRule = wildcardRule; 632 } 633 } 634 635 } 636 637 638 | Popular Tags |