1 package prefuse.data; 2 3 import java.util.Iterator ; 4 import java.util.logging.Logger ; 5 6 import prefuse.util.PrefuseConfig; 7 import prefuse.util.collections.IntIterator; 8 9 37 public class Tree extends Graph { 38 39 private static final Logger s_logger 40 = Logger.getLogger(Tree.class.getName()); 41 42 43 public static final String DEFAULT_SOURCE_KEY 44 = PrefuseConfig.get("data.tree.sourceKey"); 45 46 public static final String DEFAULT_TARGET_KEY 47 = PrefuseConfig.get("data.tree.targetKey"); 48 49 52 53 protected int m_root = -1; 54 55 58 61 public Tree() { 62 super(new Table(), false); 63 } 64 65 72 public Tree(Table nodes, Table edges) { 73 this(nodes, edges, DEFAULT_SOURCE_KEY, DEFAULT_TARGET_KEY); 74 } 75 76 87 public Tree(Table nodes, Table edges, String sourceKey, String targetKey) { 88 this(nodes, edges, DEFAULT_NODE_KEY, sourceKey, targetKey); 89 } 90 91 104 public Tree(Table nodes, Table edges, String nodeKey, 105 String sourceKey, String targetKey) 106 { 107 super(nodes, edges, false, nodeKey, sourceKey, targetKey); 108 109 for ( IntIterator rows = nodes.rows(); rows.hasNext(); ) { 110 int n = rows.nextInt(); 111 if ( getParent(n) < 0 ) { 112 m_root = n; 113 break; 114 } 115 } 116 } 117 118 122 void setRoot(Node root) { 123 m_root = root.getRow(); 124 } 125 126 129 protected Table createLinkTable() { 130 Table links = super.createLinkTable(); 131 links.addColumns(TREE_LINKS_SCHEMA); 132 return links; 133 } 134 135 138 protected void updateDegrees(int e, int s, int t, int incr) { 139 super.updateDegrees(e, s, t, incr); 140 int od = getOutDegree(s); 141 if ( incr > 0 ) { 142 m_links.setInt(t, CHILDINDEX, od-1); 144 } else if ( incr < 0 ) { 145 int[] links = (int[])m_links.get(s, OUTLINKS); 147 for ( int i=0; i<od; ++i ) { 148 int n = getTargetNode(links[i]); 149 m_links.setInt(n, CHILDINDEX, i); 150 } 151 m_links.setInt(t, CHILDINDEX, -1); 152 } 153 } 154 155 158 162 public int addRootRow() { 163 if ( getNodeCount() != 0 ) { 164 throw new IllegalStateException ( 165 "Can only add a root node to an empty tree"); 166 } 167 return (m_root = addNodeRow()); 168 } 169 170 174 public Node addRoot() { 175 return getNode(addRootRow()); 176 } 177 178 184 public int addChild(int parent) { 185 int child = super.addNodeRow(); 186 addChildEdge(parent, child); 187 return child; 188 } 189 190 196 public Node addChild(Node parent) { 197 nodeCheck(parent, true); 198 return getNode(addChild(parent.getRow())); 199 } 200 201 207 public int addChildEdge(int parent, int child) { 208 return super.addEdge(parent, child); 209 } 210 211 217 public Edge addChildEdge(Node parent, Node child) { 218 nodeCheck(parent, true); 219 nodeCheck(child, true); 220 return getEdge(addChildEdge(parent.getRow(), child.getRow())); 221 } 222 223 230 public boolean removeChildEdge(int edge) { 231 return removeChild(getTargetNode(edge)); 232 } 233 234 241 public boolean removeChildEdge(Edge e) { 242 edgeCheck(e, true); 243 return removeChild(getTargetNode(e.getRow())); 244 } 245 246 252 public boolean removeChild(int node) { 253 while ( getChildCount(node) > 0 ) { 254 removeChild(getLastChildRow(node)); 255 } 256 return removeNode(node); 257 } 258 259 265 public boolean removeChild(Node n) { 266 nodeCheck(n, true); 267 return removeChild(n.getRow()); 268 } 269 270 273 277 public int getRootRow() { 278 return m_root; 279 } 280 281 285 public Node getRoot() { 286 return (Node)m_nodeTuples.getTuple(m_root); 287 } 288 289 295 public int getChildRow(int node, int idx) { 296 int cc = getChildCount(node); 297 if ( idx < 0 || idx >= cc ) return -1; 298 int[] links = (int[])m_links.get(node, OUTLINKS); 299 return getTargetNode(links[idx]); 300 } 301 302 308 public Node getChild(Node node, int idx) { 309 int c = getChildRow(node.getRow(), idx); 310 return ( c<0 ? null : getNode(c) ); 311 } 312 313 322 public int getChildIndex(int parent, int child) { 323 if ( getParent(child) != parent ) 324 return -1; 325 return m_links.getInt(child, CHILDINDEX); 326 } 327 328 337 public int getChildIndex(Node p, Node c) { 338 return getChildIndex(p.getRow(), c.getRow()); 339 } 340 341 346 public int getFirstChildRow(int node) { 347 return getChildRow(node, 0); 348 } 349 350 355 public Node getFirstChild(Node node) { 356 return getChild(node, 0); 357 } 358 359 364 public int getLastChildRow(int node) { 365 return getChildRow(node, getChildCount(node)-1); 366 } 367 368 373 public Node getLastChild(Node node) { 374 return getChild(node, node.getChildCount()-1); 375 } 376 377 383 public int getPreviousSiblingRow(int node) { 384 int p = getParent(node); 385 if ( p < 0 ) 386 return -1; 387 int[] links = (int[])m_links.get(p, OUTLINKS); 388 int idx = m_links.getInt(node, CHILDINDEX); 389 return ( idx<=0 ? -1 : getTargetNode(links[idx-1])); 390 } 391 392 397 public Node getPreviousSibling(Node node) { 398 int n = getPreviousSiblingRow(node.getRow()); 399 return ( n<0 ? null : getNode(n) ); 400 } 401 402 408 public int getNextSiblingRow(int node) { 409 int p = getParent(node); 410 if ( p < 0 ) 411 return -1; 412 int[] links = (int[])m_links.get(p, OUTLINKS); 413 int idx = m_links.getInt(node, CHILDINDEX); 414 int max = getChildCount(p)-1; 415 return ( idx<0 || idx>=max ? -1 : getTargetNode(links[idx+1])); 416 } 417 418 423 public Node getNextSibling(Node node) { 424 int n = getNextSiblingRow(node.getRow()); 425 return ( n<0 ? null : getNode(n) ); 426 } 427 428 436 public int getDepth(int node) { 437 if ( !getNodeTable().isValidRow(node) ) 438 return -1; 439 440 int depth = 0; 441 for ( int i=node; i!=m_root && i>=0; ++depth, i=getParent(i) ); 442 return depth; 443 } 444 445 450 public int getChildCount(int node) { 451 return getOutDegree(node); 452 } 453 454 459 public int getParentEdge(int node) { 460 if ( getInDegree(node) > 0 ) { 461 int[] inlinks = (int[])m_links.get(node, INLINKS); 462 return inlinks[0]; 463 } else { 464 return -1; 465 } 466 } 467 468 473 public Edge getParentEdge(Node n) { 474 nodeCheck(n, true); 475 int pe = getParentEdge(n.getRow()); 476 return ( pe < 0 ? null : getEdge(pe) ); 477 } 478 479 484 public int getParent(int node) { 485 int pe = getParentEdge(node); 486 return ( pe < 0 ? -1 : getSourceNode(pe) ); 487 } 488 489 494 public Node getParent(Node n) { 495 int p = getParent(n.getRow()); 496 return ( p < 0 ? null : getNode(p) ); 497 } 498 499 502 509 public IntIterator childEdgeRows(int node) { 510 return super.outEdgeRows(node); 511 } 512 513 519 public Iterator childEdges(Node n) { 520 return super.outEdges(n); 521 } 522 523 528 public Iterator children(Node n) { 529 return super.outNeighbors(n); 530 } 531 532 535 539 public boolean isValidTree() { 540 int nnodes = getNodeCount(); 542 int nedges = getEdgeCount(); 543 544 if ( nnodes != nedges+1 ) { 546 s_logger.warning("Node/edge counts incorrect."); 547 return false; 548 } 549 550 int root = getRootRow(); 553 IntIterator nodes = getNodeTable().rows(); 554 while ( nodes.hasNext() ) { 555 int n = nodes.nextInt(); 556 int id = getInDegree(n); 557 if ( n==root && id > 0 ) { 558 s_logger.warning("Root node has a parent."); 559 return false; 560 } else if ( id > 1 ) { 561 s_logger.warning("Node "+n+" has multiple parents."); 562 return false; 563 } 564 } 565 566 int[] counts = new int[] { 0, nedges }; 568 isValidHelper(getRootRow(), counts); 569 if ( counts[0] > nedges ) { 570 s_logger.warning("The tree has non-tree edges in it."); 571 return false; 572 } 573 if ( counts[0] < nedges ) { 574 s_logger.warning("Not all of the tree was visited. " + 575 "Only "+counts[0]+"/"+nedges+" edges encountered"); 576 return false; 577 } 578 return true; 579 } 580 581 584 private void isValidHelper(int node, int[] counts) { 585 IntIterator edges = childEdgeRows(node); 586 int ncount = 0; 587 while ( edges.hasNext() ) { 588 int edge = edges.nextInt(); 590 ++ncount; ++counts[0]; 591 int c = getAdjacentNode(edge, node); 593 isValidHelper(c, counts); 594 if ( counts[0] > counts[1] ) 596 return; 597 } 598 } 599 600 603 613 public Tree getSpanningTree() { 614 return m_spanning==null ? this : m_spanning; 615 } 616 617 633 public Tree getSpanningTree(Node root) { 634 nodeCheck(root, true); 635 if ( m_spanning == null ) { 636 if ( m_root == root.getRow() ) { 637 return this; 638 } else { 639 m_spanning = new SpanningTree(this, root); 640 } 641 } else if ( m_spanning.getRoot() != root ) { 642 m_spanning.buildSpanningTree(root); 643 } 644 return m_spanning; 645 } 646 647 650 651 protected static final String CHILDINDEX = "_childIndex"; 652 653 protected static final Schema TREE_LINKS_SCHEMA = new Schema(); 654 static { 655 TREE_LINKS_SCHEMA.addColumn(CHILDINDEX, int.class, new Integer (-1)); 656 TREE_LINKS_SCHEMA.lockSchema(); 657 } 658 659 } | Popular Tags |