1 10 11 package com.hp.hpl.jena.reasoner.transitiveReasoner; 12 13 import com.hp.hpl.jena.graph.*; 14 import com.hp.hpl.jena.util.iterator.*; 15 import com.hp.hpl.jena.reasoner.*; 16 17 import java.util.*; 18 19 47 48 53 public class TransitiveGraphCache implements Finder { 54 55 57 protected boolean cacheTriples = false; 58 59 60 protected HashMap nodeMap = new HashMap(); 61 62 63 protected Node directPredicate; 64 65 66 protected Node closedPredicate; 67 68 69 protected Set deletesPending; 70 71 73 protected Set originalTriples = new HashSet(); 74 75 79 static interface Visitor { 80 void visit(GraphNode node, Object arg1, Object arg2); 81 } 82 83 87 private static class GraphNode { 88 89 protected Node rdfNode; 90 91 92 protected Set succ = new HashSet(); 93 94 95 protected Set pred = new HashSet(); 96 97 98 protected Set succClosed = new HashSet(); 99 100 101 protected List succClosedTriples; 102 103 105 protected Object aliases; 106 107 110 public GraphNode(Node node) { 111 rdfNode = node; 112 } 113 114 117 public boolean pathTo(GraphNode A) { 118 if (this == A) return true; 119 return succClosed.contains(A); 120 } 121 122 125 public boolean directPathTo(GraphNode A) { 126 if (this == A) return true; 127 return succ.contains(A); 128 } 129 130 134 public GraphNode leadNode() { 135 if (aliases != null && aliases instanceof GraphNode) { 136 return ((GraphNode)aliases).leadNode(); 137 } else { 138 return this; 139 } 140 } 141 142 145 public void visitPredecessors(Visitor visitor, Object arg1, Object arg2) { 146 visitor.visit(this, arg1, arg2); 147 doVisitPredecessors(visitor, arg1, arg2, new HashSet()); 148 } 149 150 154 private void doVisitPredecessors(Visitor visitor, Object arg1, Object arg2, Set seen) { 155 if (seen.add(this)) { 156 for (Iterator i = pred.iterator(); i.hasNext(); ) { 157 GraphNode pred = (GraphNode)i.next(); 158 visitor.visit(pred, arg1, arg2); 159 } 160 for (Iterator i = pred.iterator(); i.hasNext(); ) { 161 GraphNode pred = (GraphNode)i.next(); 162 pred.doVisitPredecessors(visitor, arg1, arg2, seen); 163 } 164 } 165 } 166 167 171 public Iterator iteratorOverSuccessors() { 172 return succClosed.iterator(); 173 } 174 175 179 public void assertLinkTo(GraphNode target) { 180 if (this == target) return; 181 succ.add(target); 182 target.pred.add(this); 183 clearTripleCache(); 184 } 185 186 190 public void retractLinkTo(GraphNode target) { 191 if (this == target) return; 192 succ.remove(target); 193 target.pred.remove(this); 194 clearTripleCache(); 195 } 196 197 200 public void assertIndirectLinkTo(GraphNode target) { 201 succClosed.add(target); 203 clearTripleCache(); 204 } 205 206 209 public void clearTripleCache() { 210 succClosedTriples = null; 211 } 212 213 217 public void propagateAdd(GraphNode target) { 218 Set sc = target.succClosed; 219 visitPredecessors(new Visitor() { 220 public void visit(GraphNode node, Object arg1, Object target) { 221 Set sc = (Set)arg1; 222 node.succClosed.addAll(sc); 224 node.succClosed.add(target); 225 for (Iterator i = node.succ.iterator(); i.hasNext();) { 227 GraphNode s = (GraphNode)i.next(); 228 if (sc.contains(s)) { 229 i.remove(); 230 s.pred.remove(node); 231 } 232 } 233 } 234 }, sc, target); 235 } 236 237 241 public void propagateSCC() { 242 Set visited = new HashSet(); 243 visited.add(this); 244 doVisitPredecessors(new Visitor() { 246 public void visit(GraphNode node, Object arg1, Object arg2) { 247 Set sc = (Set)arg1; 248 node.succClosed.addAll(sc); 250 for (Iterator i = node.succ.iterator(); i.hasNext();) { 252 GraphNode s = (GraphNode)i.next(); 253 if (sc.contains(s)) { 254 i.remove(); 255 s.pred.remove(node); 256 } 257 } 258 } 259 }, succClosed, null, visited); 260 } 261 262 268 public void makeLeadNodeFor(Set members) { 269 Set newSucc = new HashSet(); 271 Set newSuccClosed = new HashSet(); 272 for (Iterator i = members.iterator(); i.hasNext(); ) { 273 GraphNode n = (GraphNode)i.next(); 274 newSucc.addAll(n.succ); 275 newSuccClosed.addAll(n.succClosed); 276 } 277 newSucc.removeAll(members); 278 newSuccClosed.removeAll(members); 279 succ = newSucc; 280 succClosed = newSuccClosed; 281 282 for (Iterator i = succ.iterator(); i.hasNext();) { 284 GraphNode n = (GraphNode)i.next(); 285 n.pred.removeAll(members); 286 n.pred.add(this); 287 } 288 289 Set done = new HashSet(); 291 Set newAliases = new HashSet(); 292 for (Iterator i = members.iterator(); i.hasNext(); ) { 293 GraphNode m = (GraphNode)i.next(); 294 if (m.aliases instanceof Set) { 295 newAliases.addAll((Set)m.aliases); 296 } else { 297 newAliases.add(m); 298 } 299 } 300 this.aliases = newAliases; 301 for (Iterator i = members.iterator(); i.hasNext(); ) { 302 GraphNode n = (GraphNode)i.next(); 303 if (n != this) { 304 pred.addAll(n.pred); 305 n.relocateAllRefTo(this, done); 306 n.aliases = this; 307 } 308 } 309 pred.removeAll(members); 310 } 311 312 317 private void relocateAllRefTo(GraphNode lead, Set done) { 318 visitPredecessors(new Visitor(){ 319 public void visit(GraphNode node, Object done, Object leadIn) { 320 if (((Set)done).add(node)) { 321 GraphNode lead = (GraphNode)leadIn; 322 Set members = (Set)lead.aliases; 323 int before = node.succ.size(); 324 node.succ.removeAll(members); 325 node.succClosed.removeAll(members); 326 node.succClosed.add(lead); 327 if (node.succ.size() != before) { 328 node.succ.add(lead); 329 } 330 } 331 } 332 }, done, lead); 333 } 334 335 342 public ExtendedIterator listTriples(boolean closed, TransitiveGraphCache tgc) { 343 if (tgc.cacheTriples) { 344 return WrappedIterator.create(leadNode().triplesForSuccessors(rdfNode, closed, tgc).iterator()); 346 } else { 347 return WrappedIterator.create(leadNode().triplesForSuccessors(rdfNode, closed, tgc).iterator()); 348 } 349 } 350 351 354 private List triplesForSuccessors(Node base, boolean closed, TransitiveGraphCache tgc) { 355 Set successors = closed ? succClosed : succ; 356 ArrayList result = new ArrayList(successors.size() + 10); 357 result.add(new Triple(base, tgc.closedPredicate, base)); for (Iterator i = successors.iterator(); i.hasNext(); ) { 359 GraphNode s = (GraphNode)i.next(); 360 result.add(new Triple(base, tgc.closedPredicate, s.rdfNode)); 361 if (s.aliases instanceof Set) { 362 for (Iterator j = ((Set)s.aliases).iterator(); j.hasNext(); ) { 363 result.add(new Triple(base, tgc.closedPredicate, ((GraphNode)j.next()).rdfNode)); 364 } 365 } 366 } 367 if (aliases instanceof Set) { 368 for (Iterator j = ((Set)aliases).iterator(); j.hasNext(); ) { 369 result.add(new Triple(base, tgc.closedPredicate, ((GraphNode)j.next()).rdfNode)); 370 } 371 } 372 return result; 373 } 374 375 379 public ExtendedIterator listPredecessorTriples(boolean closed, TransitiveGraphCache tgc) { 380 return new GraphWalker(leadNode(), rdfNode, closed, tgc.closedPredicate); 381 } 382 383 386 public String toString() { 387 return "[" + rdfNode.getLocalName() + "]"; 388 } 389 390 393 public String dump() { 394 String result = rdfNode.getLocalName(); 395 if (aliases != null) { 396 if (aliases instanceof GraphNode) { 397 result = result + " leader=" + aliases + ", "; 398 } else { 399 result = result + " SCC=" + dumpSet((Set)aliases) +", "; 400 } 401 } 402 return result + " succ=" + dumpSet(succ) + ", succClose=" + dumpSet(succClosed) + ", pred=" + dumpSet(pred); 403 } 404 405 408 private String dumpSet(Set s) { 409 StringBuffer sb = new StringBuffer (); 410 sb.append("{"); 411 boolean started = false; 412 for (Iterator i = s.iterator(); i.hasNext(); ) { 413 if (started) { 414 sb.append(", "); 415 } else { 416 started = true; 417 } 418 sb.append(i.next().toString()); 419 } 420 sb.append("}"); 421 return sb.toString(); 422 } 423 424 } 426 430 private static class GraphWalker extends NiceIterator implements ExtendedIterator { 431 432 433 boolean isDeep; 434 435 436 GraphNode node; 437 438 439 Node root; 440 441 442 Node predicate; 443 444 445 Iterator iterator = null; 446 447 448 Iterator aliasIterator = null; 449 450 451 ArrayList nodeStack = new ArrayList(); 452 453 454 ArrayList iteratorStack = new ArrayList(); 455 456 457 Triple next; 458 459 460 HashSet visited = new HashSet(); 461 462 470 GraphWalker(GraphNode node, Node rdfNode, boolean closed, Node predicate) { 471 isDeep = closed; 472 this.node = node; 473 this.root = rdfNode; 474 this.predicate = predicate; 475 this.iterator = node.pred.iterator(); 476 if (node.aliases instanceof Set) { 477 aliasIterator = ((Set)node.aliases).iterator(); 478 } 479 next = new Triple(root, predicate, root); } 481 482 483 public boolean hasNext() { 484 return next != null; 485 } 486 487 488 public Object next() { 489 Object toReturn = next; 490 walkOne(); 491 return toReturn; 492 } 493 494 497 protected void walkOne() { 498 if (aliasIterator != null) { 499 if (aliasIterator.hasNext()) { 500 GraphNode nextNode = (GraphNode)aliasIterator.next(); 501 next = new Triple(nextNode.rdfNode, predicate, root); 502 return; 503 } else { 504 aliasIterator = null; 505 } 506 } 507 if (iterator.hasNext()) { 508 GraphNode nextNode = (GraphNode)iterator.next(); 509 if (visited.add(nextNode)) { 510 if (isDeep) 512 pushStack(nextNode); 513 next = new Triple(nextNode.rdfNode, predicate, root); 514 if (nextNode.aliases instanceof Set) { 515 aliasIterator = ((Set)nextNode.aliases).iterator(); 516 } 517 } else { 518 walkOne(); 520 return; 521 } 522 } else { 523 if (nodeStack.isEmpty()) { 525 next = null; 526 return; 527 } 528 popStack(); 529 walkOne(); 530 } 531 } 532 533 536 protected void pushStack(GraphNode next) { 537 nodeStack.add(node); 538 iteratorStack.add(iterator); 539 iterator = next.pred.iterator(); 540 node = next; 541 } 542 543 546 protected void popStack() { 547 int i = nodeStack.size()-1; 548 iterator = (Iterator) iteratorStack.remove(i); 549 node = (GraphNode) nodeStack.remove(i); 550 } 551 552 } 554 557 private static class FullGraphWalker extends NiceIterator implements ExtendedIterator { 558 559 560 boolean closed; 561 562 563 Iterator baseNodeIt; 564 565 566 GraphNode node; 567 568 569 Node nodeN; 570 571 572 Node predicate; 573 574 575 Iterator succIt = null; 576 577 578 Iterator aliasesIt = null; 579 580 581 Triple next; 582 583 584 FullGraphWalker(boolean closed, Node predicate, HashMap nodes) { 585 this.predicate = predicate; 586 this.closed = closed; 587 baseNodeIt = nodes.values().iterator(); 588 walkOne(); 589 } 590 591 592 public boolean hasNext() { 593 return next != null; 594 } 595 596 597 public Object next() { 598 Object toReturn = next; 599 walkOne(); 600 return toReturn; 601 } 602 603 606 protected void walkOne() { 607 if (aliasesIt != null) { 608 if (aliasesIt.hasNext()) { 609 next = new Triple(nodeN, predicate, ((GraphNode)aliasesIt.next()).rdfNode); 610 return; 611 } else { 612 aliasesIt = null; } 614 } 615 616 if (succIt != null) { 617 if (succIt.hasNext()) { 618 GraphNode succ = (GraphNode)succIt.next(); 619 if (succ.aliases instanceof Set) { 620 aliasesIt = ((Set)succ.aliases).iterator(); 621 } 622 next = new Triple(nodeN, predicate, succ.rdfNode); 623 return; 624 } else { 625 succIt = null; } 627 } 628 629 if (baseNodeIt.hasNext()) { 630 node = (GraphNode)baseNodeIt.next(); 631 nodeN = node.rdfNode; 632 succIt = (closed ? node.succClosed : node.succ).iterator(); 633 next = new Triple(nodeN, predicate, nodeN); } else { 635 next = null; } 637 } 638 639 } 641 646 public TransitiveGraphCache(Node directPredicate, Node closedPredicate) { 647 this.directPredicate = directPredicate; 648 this.closedPredicate = closedPredicate; 649 } 650 651 655 public Node getClosedPredicate() { 656 return closedPredicate; 657 } 658 659 663 public Node getDirectPredicate() { 664 return directPredicate; 665 } 666 667 670 public synchronized void addRelation(Triple t) { 671 originalTriples.add(t); 672 addRelation(t.getSubject(), t.getObject()); 673 } 674 675 678 private void addRelation(Node start, Node end) { 679 if (start.equals(end)) return; GraphNode startN = getLead(start); 681 GraphNode endN = getLead(end); 682 683 if (startN.pathTo(endN)) { 685 return; 687 } 688 689 boolean needJoin = endN.pathTo(startN); 690 Set members = null; 691 if (needJoin) { 692 members = new HashSet(); 696 members.add(endN); 697 startN.visitPredecessors(new Visitor() { 698 public void visit(GraphNode node, Object members, Object endN) { 699 if (((GraphNode)endN).pathTo(node)) ((Set)members).add(node); 700 } }, members, endN); 701 startN.makeLeadNodeFor(members); 703 startN.propagateSCC(); 705 } else { 706 startN.propagateAdd(endN); 709 startN.assertLinkTo(endN); 710 } 711 712 if (needJoin) { 713 } 715 } 716 717 720 public void removeRelation(Triple t) { 721 Node start = t.getSubject(); 722 Node end = t.getObject(); 723 if (start == end) { 724 return; } 726 GraphNode startN = getLead(start); 727 GraphNode endN = getLead(end); 728 if (startN != endN && !(startN.directPathTo(endN))) { 729 return; 731 } 732 if (deletesPending == null) { 735 deletesPending = new HashSet(); 736 } 737 deletesPending.add(t); 738 } 739 740 743 private void processDeletes() { 744 Set kernel = new HashSet(); 746 for (Iterator i = deletesPending.iterator(); i.hasNext(); ) { 747 Triple t = (Triple)i.next(); 748 GraphNode start = (GraphNode)nodeMap.get(t.getSubject()); 749 kernel.add(start); 750 } 751 752 Set pKernel = new HashSet(); 754 pKernel.addAll(kernel); 755 for (Iterator i = nodeMap.values().iterator(); i.hasNext(); ) { 756 GraphNode n = (GraphNode)i.next(); 757 for (Iterator j = kernel.iterator(); j.hasNext();) { 758 GraphNode target = (GraphNode)j.next(); 759 if (n.pathTo(target)) { 760 pKernel.add(n); break; 761 } 762 } 763 } 764 765 for (Iterator i = pKernel.iterator(); i.hasNext(); ) { 767 GraphNode n = (GraphNode)i.next(); 768 for (Iterator j = n.succ.iterator(); j.hasNext(); ) { 769 GraphNode fringe = (GraphNode)j.next(); 770 if (! pKernel.contains(fringe)) { 771 fringe.pred.remove(n); 772 } 773 } 774 n.succ.clear(); 775 n.succClosed.clear(); 776 n.pred.clear(); 777 } 778 779 originalTriples.removeAll(deletesPending); 781 deletesPending.clear(); 782 783 for (Iterator i = originalTriples.iterator(); i.hasNext(); ) { 785 Triple t = (Triple)i.next(); 786 GraphNode n = (GraphNode)nodeMap.get(t.getSubject()); 787 if (pKernel.contains(n)) { 788 addRelation(t); 789 } 790 } 791 } 792 793 804 public ExtendedIterator findWithContinuation(TriplePattern pattern, Finder continuation) { 805 Node p = pattern.getPredicate(); 806 807 if (p.isVariable()) { 808 return find(pattern).andThen(continuation.find(pattern)); 810 } else if (p.equals(directPredicate) || p.equals(closedPredicate)) { 811 return find(pattern); 813 } else { 814 return continuation.find(pattern); 816 } 817 818 } 819 820 823 public boolean contains(TriplePattern pattern) { 824 ClosableIterator it = find(pattern); 825 boolean result = it.hasNext(); 826 it.close(); 827 return result; 828 } 829 832 public ExtendedIterator listAllSubjects() { 833 return WrappedIterator.create(nodeMap.keySet().iterator()); 834 } 835 836 839 public boolean isSubject(Node node) { 840 return nodeMap.keySet().contains(node); 841 } 842 843 851 public boolean cacheAll(Finder graph, Node predicate) { 852 ExtendedIterator it = graph.find(new TriplePattern(null, predicate, null)); 853 boolean foundsome = it.hasNext(); 854 while (it.hasNext()) { 855 Triple triple = (Triple) it.next(); 856 addRelation(triple); 857 } 858 it.close(); 859 return foundsome; 860 } 861 862 868 public ExtendedIterator find(TriplePattern pattern) { 869 if (deletesPending != null && deletesPending.size() > 0) { 870 processDeletes(); 871 } 872 873 Node s = pattern.getSubject(); 874 Node p = pattern.getPredicate(); 875 Node o = pattern.getObject(); 876 877 if (p.isVariable() || p.equals(directPredicate) || p.equals(closedPredicate)) { 878 boolean closed = !p.equals(directPredicate); 879 Node pred = closedPredicate; if (s.isVariable()) { 881 if (o.isVariable()) { 882 return new FullGraphWalker(closed, closedPredicate, nodeMap); 896 } else { 897 GraphNode gn_o = (GraphNode)nodeMap.get(o); 899 if (gn_o == null) return NullIterator.instance; 900 return gn_o.listPredecessorTriples(closed, this); 901 } 902 } else { 903 GraphNode gn_s = (GraphNode)nodeMap.get(s); 904 if (gn_s == null) return NullIterator.instance; 905 if (o.isVariable()) { 906 return gn_s.listTriples(closed, this); 908 } else { 909 GraphNode gn_o = (GraphNode)nodeMap.get(o); 911 gn_s = gn_s.leadNode(); 912 if (gn_o == null) return NullIterator.instance; 913 gn_o = gn_o.leadNode(); 914 if ( closed ? gn_s.pathTo(gn_o) : gn_s.directPathTo(gn_o) ) { 915 return new SingletonIterator(new Triple(s, pred, o)); 916 } else { 917 return NullIterator.instance; 918 } 919 } 920 } 921 } else { 922 return NullIterator.instance; 924 } 925 } 926 927 932 public TransitiveGraphCache deepCopy() { 933 TransitiveGraphCache copy = new TransitiveGraphCache(directPredicate, closedPredicate); 934 Iterator i = find(new TriplePattern(null, directPredicate, null)); 935 while (i.hasNext()) { 936 Triple t = (Triple)i.next(); 937 copy.addRelation(t.getSubject(), t.getObject()); 938 } 939 return copy; 940 } 941 942 945 public void clear() { 946 nodeMap.clear(); 947 } 948 949 954 public void setCaching(boolean enable) { 955 if (! enable && cacheTriples) { 956 for (Iterator i = nodeMap.values().iterator(); i.hasNext(); ) { 958 ((GraphNode)i.next()).clearTripleCache(); 959 } 960 } 961 cacheTriples = enable; 962 } 963 964 967 public String dump() { 968 StringBuffer sb = new StringBuffer (); 969 for (Iterator i = nodeMap.values().iterator(); i.hasNext(); ) { 970 GraphNode n = (GraphNode)i.next(); 971 sb.append(n.dump()); 972 sb.append("\n"); 973 } 974 return sb.toString(); 975 } 976 977 981 985 private GraphNode getLead(Node n) { 986 GraphNode gn = (GraphNode)nodeMap.get(n); 987 if (gn == null) { 988 gn = new GraphNode(n); 989 nodeMap.put(n, gn); 990 return gn; 991 } else { 992 return gn.leadNode(); 993 } 994 } 995 996 } 997 998 999 1028 | Popular Tags |