00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 package utils;
00025
00026 import java.util.*;
00027
00028 public class DoubleLinkedDAG implements Cloneable {
00029
00030
00031
00032
00033 protected static int MARK_NOT_VISITED = 0;
00034 protected static int MARK_BEING_VISITED = 1;
00035 protected static int MARK_DONE_VISITED = 2;
00036
00037 protected ArrayList nodes = new ArrayList();
00038
00039 protected int numEdges = 0;
00040
00041
00042
00043
00044
00045 protected int[] nodeMarks;
00046
00047
00048
00049
00050
00051 protected BitSet nodesVisited;
00052
00053
00054
00055
00056
00057
00058
00059 public class MinMaxDistance {
00060 public int minDist = -1;
00061 public int maxDist = -1;
00062
00063 public MinMaxDistance(int minDist, int maxDist) {
00064 this.minDist = minDist;
00065 this.maxDist = maxDist;
00066 }
00067
00068 public String toString() {
00069 return "min: " + minDist + "; max: " + maxDist;
00070 }
00071 }
00072
00073
00074
00075
00076 public DoubleLinkedDAG() {
00077 }
00078
00079
00080
00081
00082 public DoubleLinkedDAG(DoubleLinkedDAG dag) {
00083 numEdges = dag.numEdges;
00084 nodes.ensureCapacity(dag.nodes.size());
00085
00086 Iterator itNodes = dag.nodes.iterator();
00087 while (itNodes.hasNext()) {
00088 DoubleLinkedDAGNode n = (DoubleLinkedDAGNode)itNodes.next();
00089 DoubleLinkedDAGNode clonedN = (DoubleLinkedDAGNode)n.clone();
00090 clonedN.allNodes = nodes;
00091 nodes.add(clonedN);
00092 }
00093 }
00094
00095
00096
00097
00098 public Object clone() {
00099 DoubleLinkedDAG clonedDAG = new DoubleLinkedDAG(this);
00100 return clonedDAG;
00101 }
00102
00108 public int addNode(DoubleLinkedDAGNode node) {
00109 assert(node != null);
00110
00111 nodes.add(node);
00112 node.id = nodes.size() - 1;
00113 node.allNodes = nodes;
00114
00115 return node.id;
00116 }
00117
00118 public boolean hasNode(int id) {
00119 assert(id >= 0);
00120
00121 return (id < nodes.size());
00122 }
00123
00130 public boolean hasNode(DoubleLinkedDAGNode node) {
00131 Iterator itNodes = nodes.iterator();
00132 while (itNodes.hasNext()) {
00133 DoubleLinkedDAGNode n = (DoubleLinkedDAGNode)itNodes.next();
00134 if (node == n) return true;
00135 }
00136 return false;
00137 }
00138
00145 public void addEdge(DoubleLinkedDAGNode from, DoubleLinkedDAGNode to) {
00146
00147
00148 assert(nodes.contains(from) && nodes.contains(to));
00149 assert(!from.getChildren().contains(to.id) && !to.getParents().contains(from.id));
00150
00151 from.getChildren().addSorted(to.id);
00152 to.getParents().addSorted(from.id);
00153
00154 ++numEdges;
00155 }
00156
00157 public boolean hasEdge(DoubleLinkedDAGNode from, DoubleLinkedDAGNode to) {
00158
00159 assert(nodes.contains(from) && nodes.contains(to));
00160
00161 return (from.getChildren().contains(to.id));
00162 }
00163
00164 public void removeEdge(DoubleLinkedDAGNode from, DoubleLinkedDAGNode to) {
00165 assert(hasEdge(from, to));
00166
00167 from.getChildren().remove(to.id);
00168 to.getParents().remove(from.id);
00169
00170 --numEdges;
00171 }
00172
00173 public ArrayList getNodes() {
00174 return nodes;
00175 }
00176
00177 public int getNumNodes() {
00178 return nodes.size();
00179 }
00180
00181 public int getNumEdges() {
00182 return numEdges;
00183 }
00184
00185 public String toString() {
00186 return toString(null);
00187 }
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 public String toString(GraphMatrix graphMatrix) {
00198 StringBuffer result = new StringBuffer();
00199
00200 Iterator itNodes = iterator();
00201 while (itNodes.hasNext()) {
00202 DoubleLinkedDAGNode n = (DoubleLinkedDAGNode)itNodes.next();
00203 result.append("node: ");
00204 result.append(n.toString());
00205 result.append("; PARENTS: ");
00206
00207 Iterator itParents = n.getParentsIterator();
00208 while (itParents.hasNext()) {
00209 DoubleLinkedDAGNode parent = (DoubleLinkedDAGNode)itParents.next();
00210 result.append(parent.toString());
00211 if (graphMatrix != null) {
00212 Object tag = graphMatrix.getTag(parent.id, n.id);
00213 if (tag != null) {
00214 result.append("(");
00215 result.append(tag.toString());
00216 result.append(")");
00217 }
00218 }
00219 result.append("; ");
00220 }
00221
00222 result.append("; CHILDREN: ");
00223 Iterator itChildren = n.getChildrenIterator();
00224 while (itChildren.hasNext()) {
00225 DoubleLinkedDAGNode child = (DoubleLinkedDAGNode)itChildren.next();
00226 result.append(child.toString());
00227 if (graphMatrix != null) {
00228 Object tag = graphMatrix.getTag(n.id, child.id);
00229 if (tag != null) {
00230 result.append("(");
00231 result.append(tag.toString());
00232 result.append(")");
00233 }
00234 }
00235 result.append("; ");
00236 }
00237
00238 result.append("\n");
00239 }
00240
00241 return result.toString();
00242 }
00243
00244 public String toStringShort() {
00245
00246 StringBuffer result = new StringBuffer();
00247 AddNodeAsStringVisitor visitor = new AddNodeAsStringVisitor(result);
00248 visitRoots(visitor, false);
00249 return result.toString();
00250 }
00251
00252
00253
00254
00255
00256
00257
00258 public Iterator iterator() {
00259 return nodes.iterator();
00260 }
00261
00262
00263
00264
00265 public final DoubleLinkedDAGNode getNode(int index) {
00266 return (DoubleLinkedDAGNode)nodes.get(index);
00267 }
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 public void visitChildrenPreOrder(DoubleLinkedDAGNode node,
00278 DoubleLinkedDAGVisitor visitor, boolean visitOnlyOnce) {
00279
00280 if (visitOnlyOnce) nodesVisited = new BitSet(nodes.size());
00281 visitChildrenPreOrder_Recursive(node, visitor, visitOnlyOnce);
00282 nodesVisited = null;
00283 }
00284
00285 public void visitChildrenPreOrder_Recursive(DoubleLinkedDAGNode node,
00286 DoubleLinkedDAGVisitor visitor, boolean visitOnlyOnce) {
00287
00288 if (!visitOnlyOnce || !nodesVisited.get(node.id)) {
00289
00290 visitor.visit(node);
00291 if (visitOnlyOnce) {
00292 nodesVisited.set(node.id, true);
00293 }
00294 boolean moreNodes = visitor.wantMoreNodes();
00295
00296 if (moreNodes) {
00297
00298 Iterator itChildren = node.getChildrenIterator();
00299 while (moreNodes && itChildren.hasNext()) {
00300 DoubleLinkedDAGNode child = (DoubleLinkedDAGNode)itChildren.next();
00301 visitChildrenPreOrder_Recursive(child, visitor, visitOnlyOnce);
00302 moreNodes = visitor.wantMoreNodes();
00303 }
00304 }
00305 }
00306 }
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318 public void visitRoots(DoubleLinkedDAGVisitor visitor, boolean visitOnlyOnce) {
00319 Iterator itNodes = iterator();
00320 while (itNodes.hasNext()) {
00321 DoubleLinkedDAGNode node = (DoubleLinkedDAGNode)itNodes.next();
00322 if (!node.hasParents()) {
00323 visitChildrenPreOrder(node, visitor, visitOnlyOnce);
00324 }
00325 }
00326 }
00327
00328
00329
00330
00331
00332
00333 protected int computeMaxPathLen_Recursive(DoubleLinkedDAGNode root) {
00334 int maxLen = 0;
00335
00336 Iterator itChildren = root.getChildrenIterator();
00337 while (itChildren.hasNext()) {
00338 DoubleLinkedDAGNode child = (DoubleLinkedDAGNode)itChildren.next();
00339 int tmpMax = 1 + computeMaxPathLen_Recursive(child);
00340 if (tmpMax > maxLen) maxLen = tmpMax;
00341 }
00342
00343 return maxLen;
00344 }
00345
00346
00347
00348
00349
00350
00351
00352 public int computeMaxPathLen() {
00353 int maxLen = 0;
00354
00355 Iterator itNodes = iterator();
00356 while (itNodes.hasNext()) {
00357 DoubleLinkedDAGNode n = (DoubleLinkedDAGNode)itNodes.next();
00358
00359 if (!n.hasParents()) {
00360 int tmpMax = computeMaxPathLen_Recursive(n);
00361 if (tmpMax > maxLen) maxLen = tmpMax;
00362 }
00363 }
00364
00365 return maxLen;
00366 }
00367
00368
00369
00370
00371
00372 protected void transClosureRecursion(GraphMatrix closure, DoubleLinkedDAGNode n,
00373 DoubleLinkedDAGNode descendant,
00374 boolean computeMinMaxDist, int distance) {
00375
00376 boolean recursionRequired;
00377
00378
00379
00380
00381
00382
00383
00384 if (closure.hasEdge(n.id, descendant.id)) {
00385 if (computeMinMaxDist) {
00386 MinMaxDistance d = (MinMaxDistance)closure.getTag(n.id, descendant.id);
00387 assert(d.minDist <= d.maxDist);
00388
00389 if (distance < d.minDist) {
00390 System.out.println("distance < d.minDist: " + distance + " < " + d.minDist);
00391 closure.setTag(n.id, descendant.id, new MinMaxDistance(distance, d.maxDist));
00392 recursionRequired = true;
00393 } else if (distance > d.maxDist) {
00394 System.out.println("distance > d.maxDist: " + distance + " > " + d.maxDist);
00395 closure.setTag(n.id, descendant.id, new MinMaxDistance(d.minDist, distance));
00396 recursionRequired = true;
00397 } else recursionRequired = false;
00398
00399 } else {
00400 recursionRequired = false;
00401 }
00402 } else {
00403 closure.addEdge(n.id, descendant.id);
00404 if (computeMinMaxDist) closure.setTag(n.id, descendant.id, new MinMaxDistance(distance, distance));
00405
00406 recursionRequired = true;
00407 }
00408
00409
00410
00411 if (recursionRequired) {
00412 Iterator itChildren = descendant.getChildrenIterator();
00413 while (itChildren.hasNext()) {
00414 DoubleLinkedDAGNode child = (DoubleLinkedDAGNode)itChildren.next();
00415 transClosureRecursion(closure, n, child, computeMinMaxDist, distance + 1);
00416 }
00417 }
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 public GraphMatrix computeTransitiveClosure(boolean computeMinMaxDist) {
00430
00431 final GraphMatrix result = new GraphMatrix(nodes.size());
00432
00433
00434
00435 int progress = 0;
00436 Iterator itNodes = nodes.iterator();
00437 while (itNodes.hasNext()) {
00438 final DoubleLinkedDAGNode n = (DoubleLinkedDAGNode)itNodes.next();
00439
00440
00441
00442 Iterator itChildren = n.getChildrenIterator();
00443 while (itChildren.hasNext()) {
00444 DoubleLinkedDAGNode child = (DoubleLinkedDAGNode)itChildren.next();
00445
00446
00447 transClosureRecursion(result, n, child, computeMinMaxDist, 1);
00448 }
00449
00450 ++progress;
00451 }
00452
00453
00454
00455
00456 return result;
00457
00458 }
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470 public boolean correctTransitiveClosure(GraphMatrix transClosure, boolean checkMinMaxDist) {
00471
00472
00473
00474
00475
00476 for (int i = 0; i < nodes.size(); ++i) {
00477 for (int j = i + 1; j < nodes.size(); ++j) {
00478
00479 DoubleLinkedDAGNode ni = (DoubleLinkedDAGNode)nodes.get(i);
00480 DoubleLinkedDAGNode nj = (DoubleLinkedDAGNode)nodes.get(j);
00481
00482 if (isAncestor(ni, nj)) {
00483 if (!transClosure.hasEdge(ni.id, nj.id)) return false;
00484 } else if (isAncestor(nj, ni)) {
00485 if (!transClosure.hasEdge(nj.id, ni.id)) return false;
00486 }
00487 }
00488 }
00489
00490
00491 Iterator itEdges = transClosure.getEdgeIterator();
00492 while (itEdges.hasNext()) {
00493 GraphMatrix.Edge e = (GraphMatrix.Edge)itEdges.next();
00494 DoubleLinkedDAGNode ni = (DoubleLinkedDAGNode)nodes.get(e.from);
00495 DoubleLinkedDAGNode nj = (DoubleLinkedDAGNode)nodes.get(e.to);
00496
00497 if (!isAncestor(ni, nj)) return false;
00498 else if (checkMinMaxDist) {
00499 Object tag = transClosure.getTag(ni.id, nj.id);
00500 assert(tag != null);
00501 MinMaxDistance minMaxDist = (MinMaxDistance)tag;
00502
00503 int computedMinDist = computeMinDistance(ni, nj);
00504 if (minMaxDist.minDist != computedMinDist) return false;
00505
00506 int computedMaxDist = computeMaxDistance(ni, nj);
00507 if (minMaxDist.maxDist != computedMaxDist) return false;
00508 }
00509
00510 }
00511
00512 return true;
00513
00514 }
00515
00516
00517
00518
00519
00520
00521 public int computeMinDistance(DoubleLinkedDAGNode fromNode, DoubleLinkedDAGNode toNode) {
00522
00523 int minDist;
00524
00525 if (fromNode == toNode) minDist = 0;
00526 else {
00527 Iterator itChildren = fromNode.getChildrenIterator();
00528 if (!itChildren.hasNext()) minDist = -1;
00529 else {
00530 minDist = -1;
00531
00532 while (itChildren.hasNext()) {
00533 DoubleLinkedDAGNode child = (DoubleLinkedDAGNode)itChildren.next();
00534 int childDist = computeMinDistance(child, toNode);
00535 if (childDist == 0) {
00536 minDist = 1;
00537 break;
00538 } else {
00539 if (childDist > 0) {
00540 if (minDist == -1) minDist = childDist + 1;
00541 else if (childDist + 1 < minDist) minDist = childDist + 1;
00542 }
00543 }
00544 }
00545 }
00546 }
00547
00548 return minDist;
00549 }
00550
00551
00552
00553
00554
00555
00556
00557 public int computeMaxDistance(DoubleLinkedDAGNode fromNode, DoubleLinkedDAGNode toNode) {
00558
00559 int maxDist;
00560
00561 if (fromNode == toNode) maxDist = 0;
00562 else {
00563 Iterator itChildren = fromNode.getChildrenIterator();
00564 if (!itChildren.hasNext()) maxDist = -1;
00565 else {
00566 maxDist = -1;
00567
00568 while (itChildren.hasNext()) {
00569 DoubleLinkedDAGNode child = (DoubleLinkedDAGNode)itChildren.next();
00570 int childDist = computeMaxDistance(child, toNode);
00571
00572 if (childDist == 0) {
00573 if (maxDist == -1) maxDist = 1;
00574 else assert(maxDist >= 1);
00575 } else if (childDist > 0) {
00576 if (maxDist == -1) maxDist = childDist + 1;
00577 else if (childDist + 1 > maxDist) maxDist = childDist + 1;
00578 }
00579
00580 }
00581 }
00582 }
00583
00584 return maxDist;
00585 }
00586
00587
00588
00589
00590
00591 public void updateTransClosureForNewEdge(GraphMatrix transClosure,
00592 DoubleLinkedDAGNode fromNode, DoubleLinkedDAGNode toNode,
00593 boolean computeMinDistance) {
00594
00595
00596
00597
00598 Iterator itNodes = nodes.iterator();
00599 while (itNodes.hasNext())
00600 {
00601 DoubleLinkedDAGNode n = (DoubleLinkedDAGNode)itNodes.next();
00602 if ((n == fromNode) || (transClosure.hasEdge(n.id, fromNode.id))) {
00603 transClosureRecursion(transClosure, n, toNode, computeMinDistance, 1);
00604 }
00605 }
00606
00607 }
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618 public boolean isAncestor(DoubleLinkedDAGNode possAnc, DoubleLinkedDAGNode possDesc) {
00619
00620
00621 assert(nodes.contains(possAnc) && nodes.contains(possDesc));
00622
00623 SearchNodeVisitor visitor = new SearchNodeVisitor(possDesc);
00624
00625 Iterator itChildren = possAnc.getChildrenIterator();
00626 while (itChildren.hasNext() && !visitor.foundNode()) {
00627 DoubleLinkedDAGNode child = (DoubleLinkedDAGNode)itChildren.next();
00628 visitChildrenPreOrder(child, visitor, true);
00629 }
00630
00631 return visitor.foundNode();
00632 }
00633
00634
00635
00636
00637
00638
00639
00640 public boolean isAncestor(DoubleLinkedDAGNode possAnc, DoubleLinkedDAGNode possDesc,
00641 GraphMatrix transitiveClosure) {
00642
00643
00644 assert(nodes.contains(possAnc) && nodes.contains(possDesc));
00645
00646 boolean result = transitiveClosure.hasEdge(possAnc.id, possDesc.id);
00647
00648
00649 assert(result == isAncestor(possAnc, possDesc));
00650
00651 return result;
00652 }
00653
00654
00655
00656
00657
00658
00659
00660
00661 protected DoubleLinkedDAGNode findCycle_Recursive(DoubleLinkedDAGNode n, ArrayList foundCycle) {
00662
00663 int nodeStatus = nodeMarks[n.id];
00664
00665 if (nodeStatus == MARK_BEING_VISITED) {
00666 foundCycle.add(n);
00667 return n;
00668
00669 } else {
00670
00671 if (nodeStatus == MARK_DONE_VISITED) {
00672 return null;
00673
00674 } else {
00675 nodeMarks[n.id] = MARK_BEING_VISITED;
00676
00677
00678
00679 Iterator itChildren = n.getChildrenIterator();
00680 while (itChildren.hasNext()) {
00681 DoubleLinkedDAGNode child = (DoubleLinkedDAGNode)itChildren.next();
00682 DoubleLinkedDAGNode cycleNode = findCycle_Recursive(child, foundCycle);
00683
00684 if (cycleNode != null) {
00685
00686 if (cycleNode == n) {
00687 foundCycle.add(n);
00688 return null;
00689
00690 } else {
00691 foundCycle.add(n);
00692 return n;
00693 }
00694 }
00695 }
00696 }
00697
00698 nodeMarks[n.id] = MARK_DONE_VISITED;
00699 return null;
00700 }
00701
00702 }
00703
00704
00705
00706
00707
00708
00709
00710 public List findCycle() {
00711
00712 ArrayList foundCycle = new ArrayList();
00713 nodeMarks = new int[nodes.size()];
00714
00715
00716
00717 Iterator itNodes = nodes.iterator();
00718 while (itNodes.hasNext()) {
00719 DoubleLinkedDAGNode n = (DoubleLinkedDAGNode)itNodes.next();
00720
00721 if (!n.hasParents()) {
00722
00723
00724
00725 for (int i = 0; i < nodeMarks.length; ++i) {
00726 nodeMarks[i] = MARK_NOT_VISITED;
00727 }
00728
00729
00730
00731 findCycle_Recursive(n, foundCycle);
00732 if (foundCycle.size() > 0) break;
00733 }
00734 }
00735
00736 if (foundCycle.size() == 0) return null;
00737 else return foundCycle;
00738
00739 }
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749 public Iterator getAncestorIterator(DoubleLinkedDAGNode node, GraphMatrix transitiveClosure) {
00750 return new IntegerIterator(transitiveClosure.getAncestorIterator(node.id));
00751 }
00752
00753
00754
00755
00756
00757
00758 public Iterator getDescendantIterator(DoubleLinkedDAGNode node, GraphMatrix transitiveClosure) {
00759 return new IntegerIterator(transitiveClosure.getDescendantIterator(node.id));
00760 }
00761
00762
00763
00764
00765
00766
00767 protected class IntegerIterator implements Iterator {
00768
00769 Iterator itNodes;
00770
00771
00772
00773
00774 public IntegerIterator(Iterator itNodes) {
00775 this.itNodes = itNodes;
00776 }
00777
00778 public boolean hasNext() {
00779 return itNodes.hasNext();
00780 }
00781
00782 public Object next() {
00783 assert(hasNext());
00784
00785 Integer index = (Integer)itNodes.next();
00786 return nodes.get(index.intValue());
00787 }
00788
00789 public void remove() {
00790 throw new UnsupportedOperationException();
00791 }
00792 }
00793
00794 }
00795
00796 class SearchNodeVisitor extends DoubleLinkedDAGVisitor {
00797
00798 private DoubleLinkedDAGNode searchNode;
00799
00800 private boolean foundNode = false;
00801
00802
00803 public SearchNodeVisitor(DoubleLinkedDAGNode searchNode) {
00804 this.searchNode = searchNode;
00805 }
00806
00807 public boolean wantMoreNodes() {
00808 return (!foundNode);
00809 }
00810
00811 public void visit(DoubleLinkedDAGNode node) {
00812 if (node == searchNode) foundNode = true;
00813 }
00814
00815 public boolean foundNode() {
00816 return foundNode;
00817 }
00818
00819 }
00820
00821
00822
00823
00824
00825
00826 class AddNodeAsStringVisitor extends DoubleLinkedDAGVisitor {
00827
00828 StringBuffer str;
00829
00830 public AddNodeAsStringVisitor(StringBuffer str) {
00831 this.str = str;
00832 }
00833
00834 public boolean wantMoreNodes() {
00835 return true;
00836 }
00837
00838 public void visit(DoubleLinkedDAGNode node) {
00839 Iterator itParents = node.getParentsIterator();
00840 if (!itParents.hasNext()) {
00841 str.append(node.toString() + "; ");
00842 }
00843 while (itParents.hasNext()) {
00844 DoubleLinkedDAGNode parentNode = (DoubleLinkedDAGNode)itParents.next();
00845 str.append(parentNode.toString() + " => " + node.toString() + "; ");
00846 }
00847 }
00848
00849 public String getStr() {
00850 return str.toString();
00851 }
00852
00853 }
00854