1 package org.thegalactic.dgraph;
2
3
4
5
6
7
8
9
10
11
12
13
14 import java.util.AbstractSet;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.Comparator;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.NoSuchElementException;
22 import java.util.Set;
23 import java.util.SortedSet;
24 import java.util.TreeMap;
25 import java.util.TreeSet;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 public class ConcreteDGraph<N, E> extends AbstractDGraph<N, E> implements Cloneable {
63
64
65
66
67
68
69
70 private TreeSet<Node<N>> nodes;
71
72
73
74
75
76
77 private TreeMap<Node<N>, TreeSet<Edge<N, E>>> successors;
78
79
80
81
82 private TreeMap<Node<N>, TreeSet<Edge<N, E>>> predecessors;
83
84
85
86
87
88
89
90
91 public ConcreteDGraph() {
92 super();
93 this.nodes = new TreeSet<Node<N>>();
94 this.successors = new TreeMap<Node<N>, TreeSet<Edge<N, E>>>();
95 this.predecessors = new TreeMap<Node<N>, TreeSet<Edge<N, E>>>();
96 }
97
98
99
100
101
102
103
104
105
106 public ConcreteDGraph(final SortedSet<Node<N>> set) {
107 this();
108 this.nodes.addAll(set);
109 for (final Node<N> node : this.nodes) {
110 this.successors.put(node, new TreeSet<Edge<N, E>>());
111 this.predecessors.put(node, new TreeSet<Edge<N, E>>());
112 }
113 }
114
115
116
117
118
119
120 public ConcreteDGraph(final DGraph<N, E> graph) {
121 this(graph.getNodes());
122 for (final Edge<N, E> edge : graph.getEdges()) {
123 this.addEdge(edge);
124 }
125 }
126
127
128
129
130
131
132
133
134
135
136
137
138 @Override
139 public ConcreteDGraph<N, E> clone() throws CloneNotSupportedException {
140 final ConcreteDGraph<N, E> graph = (ConcreteDGraph<N, E>) super.clone();
141 graph.nodes = (TreeSet) this.nodes.clone();
142 graph.successors = new TreeMap<Node<N>, TreeSet<Edge<N, E>>>();
143 graph.predecessors = new TreeMap<Node<N>, TreeSet<Edge<N, E>>>();
144 for (final Map.Entry<Node<N>, TreeSet<Edge<N, E>>> entry : this.successors.entrySet()) {
145 graph.successors.put(entry.getKey(), (TreeSet<Edge<N, E>>) entry.getValue().clone());
146 }
147 for (final Map.Entry<Node<N>, TreeSet<Edge<N, E>>> entry : this.predecessors.entrySet()) {
148 graph.predecessors.put(entry.getKey(), (TreeSet<Edge<N, E>>) entry.getValue().clone());
149 }
150 return graph;
151 }
152
153
154
155
156
157
158 public final SortedSet<Node<N>> getNodes() {
159 return Collections.unmodifiableSortedSet(this.nodes);
160 }
161
162
163
164
165
166
167 public final SortedSet<Edge<N, E>> getEdges() {
168 return new Edges(this);
169 }
170
171
172
173
174
175
176
177
178 public final SortedSet<Edge<N, E>> getSuccessorEdges(final Node<N> node) {
179 return Collections.unmodifiableSortedSet(this.successors.get(node));
180 }
181
182
183
184
185
186
187
188
189 public final SortedSet<Edge<N, E>> getPredecessorEdges(final Node<N> node) {
190 return Collections.unmodifiableSortedSet(this.predecessors.get(node));
191 }
192
193
194
195
196
197
198
199
200
201
202
203 public final SortedSet<Node<N>> getSuccessorNodes(final Node<N> node) {
204 final SortedSet<Node<N>> successorsFromNode = new TreeSet<Node<N>>();
205 for (final Edge<N, E> edge : this.successors.get(node)) {
206 successorsFromNode.add(edge.getTarget());
207 }
208 return Collections.unmodifiableSortedSet(successorsFromNode);
209 }
210
211
212
213
214
215
216
217
218
219
220
221 public final SortedSet<Node<N>> getPredecessorNodes(final Node<N> node) {
222 final SortedSet<Node<N>> predecessorsFromNode = new TreeSet<Node<N>>();
223 for (final Edge<N, E> edge : this.predecessors.get(node)) {
224 predecessorsFromNode.add(edge.getSource());
225 }
226 return Collections.unmodifiableSortedSet(predecessorsFromNode);
227 }
228
229
230
231
232
233
234
235
236
237
238
239 public final Edge<N, E> getEdge(final Node<N> source, final Node<N> target) {
240 Edge<N, E> edge = null;
241 if (source != null && target != null) {
242 try {
243 final Edge<N, E> search = new Edge<N, E>(source, target);
244 edge = this.successors.get(source).subSet(search, true, search, true).first();
245 } catch (NoSuchElementException ex) {
246 }
247 }
248 return edge;
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262 public final Node<N> getNode(final Node<N> search) {
263 for (final Node<N> node : this.nodes) {
264 if (node.equals(search)) {
265 return node;
266 }
267 }
268 return null;
269 }
270
271
272
273
274
275
276
277
278
279
280
281
282 public final Node<N> getNodeByContent(final Object content) {
283 for (final Node<N> node : this.nodes) {
284 if (node.getContent().equals(content)) {
285 return node;
286 }
287 }
288 return null;
289 }
290
291
292
293
294
295
296
297
298 public final Node<N> getNodeByIdentifier(int identifier) {
299 for (final Node<N> node : this.nodes) {
300 if (node.getIdentifier() == identifier) {
301 return node;
302 }
303 }
304 return null;
305 }
306
307
308
309
310
311
312 public final int sizeNodes() {
313 return this.nodes.size();
314 }
315
316
317
318
319
320
321 public final int sizeEdges() {
322 int size = 0;
323 for (final Node<N> node : this.nodes) {
324 size += this.successors.get(node).size();
325 }
326 return size;
327 }
328
329
330
331
332
333
334
335
336
337
338
339
340 public final boolean containsNode(final Node<N> node) {
341 return this.nodes.contains(node);
342 }
343
344
345
346
347
348
349
350
351 public final boolean addNode(final Node<N> node) {
352 if (!this.containsNode(node)) {
353 this.nodes.add(node);
354 this.successors.put(node, new TreeSet<Edge<N, E>>());
355 this.predecessors.put(node, new TreeSet<Edge<N, E>>());
356 return true;
357 }
358 return false;
359 }
360
361
362
363
364
365
366
367
368 public final boolean removeNode(final Node<N> node) {
369 if (this.containsNode(node)) {
370
371 for (final Edge<N, E> successor : this.successors.get(node)) {
372 if (successor.getTarget().compareTo(node) != 0) {
373 for (final Edge<N, E> predecessor : this.predecessors.get(successor.getTarget())) {
374 if (predecessor.getSource().compareTo(node) == 0) {
375 this.predecessors.get(successor.getTarget()).remove(predecessor);
376 }
377 }
378 }
379 this.successors.remove(node);
380 }
381
382 for (final Edge<N, E> predecessor : this.predecessors.get(node)) {
383 if (predecessor.getSource().compareTo(node) != 0) {
384 for (final Edge<N, E> successor : this.successors.get(predecessor.getSource())) {
385 if (successor.getTarget().compareTo(node) == 0) {
386 this.successors.get(predecessor.getSource()).remove(successor);
387 }
388 }
389 }
390 this.predecessors.remove(node);
391 }
392
393 this.nodes.remove(node);
394 return true;
395 }
396 return false;
397 }
398
399
400
401
402
403
404
405
406 public final boolean removeNodes(final Set<Node<N>> nodes) {
407 boolean all = true;
408 for (final Node<N> node : nodes) {
409 if (!this.removeNode(node)) {
410 all = false;
411 }
412 }
413 return all;
414 }
415
416
417
418
419
420
421
422
423
424 public final boolean containsEdge(final Node<N> source, final Node<N> target) {
425 return this.containsNode(source)
426 && this.containsNode(target)
427 && this.getSuccessorNodes(source).contains(target)
428 && this.getPredecessorNodes(target).contains(source);
429 }
430
431
432
433
434
435
436
437
438 public final boolean containsEdge(final Edge<N, E> edge) {
439 return this.containsEdge(edge.getSource(), edge.getTarget());
440 }
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455 public final boolean addEdge(final Node<N> source, final Node<N> target, final Object content) {
456 if (this.containsNode(source) && this.containsNode(target)) {
457 final Edge<N, E> edge = new Edge(source, target, content);
458 this.successors.get(source).add(edge);
459 this.predecessors.get(target).add(edge);
460 return true;
461 }
462 return false;
463 }
464
465
466
467
468
469
470
471
472
473
474
475
476
477 public final boolean addEdge(final Node<N> source, final Node<N> target) {
478 return this.addEdge(source, target, null);
479 }
480
481
482
483
484
485
486
487
488
489
490
491
492 public final boolean addEdge(final Edge<N, E> edge) {
493 if (this.containsNode(edge.getSource()) && this.containsNode(edge.getTarget())) {
494 this.successors.get(edge.getSource()).add(edge);
495 this.predecessors.get(edge.getTarget()).add(edge);
496 return true;
497 }
498 return false;
499 }
500
501
502
503
504
505
506
507
508
509
510
511
512
513 public final boolean removeEdge(final Node<N> source, final Node<N> target) {
514 if (this.containsEdge(source, target)) {
515 final Edge<N, E> edge = new Edge(source, target);
516 this.successors.get(source).remove(edge);
517 this.predecessors.get(target).remove(edge);
518 return true;
519 }
520 return false;
521 }
522
523
524
525
526
527
528
529
530
531 public final boolean removeEdge(final Edge<N, E> edge) {
532 if (this.containsEdge(edge)) {
533 this.successors.get(edge.getSource()).remove(edge);
534 this.predecessors.get(edge.getTarget()).remove(edge);
535 return true;
536 }
537 return false;
538 }
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556 public ConcreteDGraph<N, E> getSubgraphByNodes(final Set<Node<N>> nodes) {
557 ConcreteDGraph<N, E> graph = new ConcreteDGraph<N, E>();
558
559 for (Node<N> node : nodes) {
560 if (this.containsNode(node)) {
561 graph.addNode(node);
562 }
563 }
564
565 for (Edge<N, E> edge : this.getEdges()) {
566 if (graph.containsNode(edge.getTarget())) {
567 graph.addEdge(edge);
568 }
569 }
570 return graph;
571 }
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586 public ConcreteDGraph<N, E> getSubgraphByEdges(final Set<Edge<N, E>> edges) {
587 ConcreteDGraph<N, E> graph = new ConcreteDGraph<N, E>();
588
589 for (Node<N> node : this.nodes) {
590 graph.addNode(node);
591 }
592
593 for (Edge<N, E> edge : edges) {
594 if (this.containsEdge(edge)) {
595 graph.addEdge(edge);
596 }
597 }
598 return graph;
599 }
600
601
602
603
604
605
606
607 public void complementary() {
608 for (Node<N> source : this.nodes) {
609 TreeSet<Node<N>> newSuccessors = new TreeSet<Node<N>>(this.nodes);
610 newSuccessors.removeAll(this.getSuccessorNodes(source));
611 TreeSet<Node<N>> oldSuccessors = new TreeSet<Node<N>>(this.getSuccessorNodes(source));
612 for (Node<N> target : oldSuccessors) {
613 this.removeEdge(source, target);
614 }
615 for (Node<N> target : newSuccessors) {
616 this.addEdge(source, target);
617 }
618 }
619 }
620
621
622
623
624
625
626
627
628
629 public final int reflexiveReduction() {
630 int size = 0;
631 for (final Node<N> node : this.nodes) {
632 if (this.containsEdge(node, node)) {
633 size++;
634 this.removeEdge(node, node);
635 }
636 }
637 return size;
638 }
639
640
641
642
643
644
645 public final int reflexiveClosure() {
646 int size = 0;
647 for (final Node<N> node : this.nodes) {
648 if (!this.containsEdge(node, node)) {
649 size++;
650 this.addEdge(node, node);
651 }
652 }
653 return size;
654 }
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669 public int transitiveClosure() {
670 int size = 0;
671
672 final TreeMap<Node<N>, Boolean> mark = new TreeMap<Node<N>, Boolean>();
673 for (final Node<N> node : this.nodes) {
674 mark.put(node, Boolean.FALSE);
675 }
676
677 final List<Node<N>> list = new ArrayList<Node<N>>();
678 for (final Node<N> source : this.nodes) {
679 list.clear();
680 list.add(source);
681 while (!list.isEmpty()) {
682
683 final Node<N> source2 = list.remove(0);
684 for (final Node<N> target : this.getSuccessorNodes(source2)) {
685
686 if (!mark.get(target)) {
687 mark.put(target, Boolean.TRUE);
688 this.addEdge(source, target);
689 list.add(target);
690 size++;
691 }
692 }
693 }
694 for (final Node<N> target : this.getSuccessorNodes(source)) {
695 mark.put(target, Boolean.FALSE);
696 }
697 }
698 return size;
699 }
700
701
702
703
704
705 public final void transpose() {
706 ConcreteDGraph<N, E> tmp = new ConcreteDGraph<N, E>(this);
707 for (Edge<N, E> edge : tmp.getEdges()) {
708 this.removeEdge(edge);
709 this.addEdge(new Edge(edge.getTarget(), edge.getSource(), edge.getContent()));
710 }
711 }
712
713
714
715
716
717
718
719
720
721
722
723 public DAGraph<SortedSet<Node<N>>, Object> getStronglyConnectedComponent() {
724 DAGraph<SortedSet<Node<N>>, Object> cc = new DAGraph<SortedSet<Node<N>>, Object>();
725
726 ConcreteDGraph<N, E> tmp = new ConcreteDGraph<N, E>(this);
727 tmp.transitiveClosure();
728 ArrayList<Node<N>> last = tmp.depthFirstSearch()[1];
729
730 ConcreteDGraph<N, E> transposedGraph = new ConcreteDGraph<N, E>(this);
731 transposedGraph.transpose();
732
733 ArrayList<Node<N>> sort = new ArrayList<Node<N>>();
734 Object[] array = last.toArray();
735 for (int i = array.length - 1; i >= 0; i--) {
736 sort.add((Node<N>) array[i]);
737 }
738
739 TreeSet<Node<N>> visited = new TreeSet<Node<N>>();
740 for (Node<N> node : sort) {
741 if (!visited.contains(node)) {
742 last = transposedGraph.depthFirstSearch(node, visited, sort)[1];
743 visited.addAll(last);
744 TreeSet<Node<N>> sCC = new TreeSet<Node<N>>(last);
745
746 cc.addNode(new Node<SortedSet<Node<N>>>(sCC));
747 }
748 }
749
750 for (Node<SortedSet<Node<N>>> ccSource : cc.getNodes()) {
751 for (Node<SortedSet<Node<N>>> ccTarget : cc.getNodes()) {
752 for (Node<N> source : ccSource.getContent()) {
753 for (Node<N> target : ccTarget.getContent()) {
754 if (tmp.getSuccessorNodes(source).contains(target)) {
755 cc.addEdge(ccSource, ccTarget);
756 }
757 }
758 }
759 }
760 }
761 cc.reflexiveReduction();
762 return cc;
763 }
764
765
766
767
768
769
770
771
772 protected ConcreteDGraph<N, E> setNodes(final TreeSet<Node<N>> nodes) {
773 this.nodes = nodes;
774 return this;
775 }
776
777
778
779
780
781
782 protected TreeMap<Node<N>, TreeSet<Edge<N, E>>> getSuccessors() {
783 return this.successors;
784 }
785
786
787
788
789
790
791
792
793 protected ConcreteDGraph<N, E> setSuccessors(final TreeMap<Node<N>, TreeSet<Edge<N, E>>> successors) {
794 this.successors = successors;
795 return this;
796 }
797
798
799
800
801
802
803 protected TreeMap<Node<N>, TreeSet<Edge<N, E>>> getPredecessors() {
804 return this.predecessors;
805 }
806
807
808
809
810
811
812
813
814 protected ConcreteDGraph<N, E> setPredecessors(final TreeMap<Node<N>, TreeSet<Edge<N, E>>> predecessors) {
815 this.predecessors = predecessors;
816 return this;
817 }
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833 private ArrayList<Node<N>>[] depthFirstSearch(Node<N> source, TreeSet<Node<N>> visited, ArrayList<Node<N>> sort) {
834 ArrayList<Node<N>> first = new ArrayList<Node<N>>();
835 ArrayList<Node<N>> last = new ArrayList<Node<N>>();
836 first.add(source);
837 visited.add(source);
838 ArrayList<Node<N>>[] arrayVisited = new ArrayList[2];
839 if (sort != null) {
840
841 for (Node<N> node : sort) {
842 if (this.getSuccessorNodes(source).contains(node) && !visited.contains(node)) {
843 arrayVisited = this.depthFirstSearch(node, visited, sort);
844 visited.addAll(arrayVisited[0]);
845 first.addAll(arrayVisited[0]);
846 last.addAll(arrayVisited[1]);
847 }
848 }
849 } else {
850
851 for (Node<N> node : this.getSuccessorNodes(source)) {
852 if (!visited.contains(node)) {
853 arrayVisited = this.depthFirstSearch(node, visited, sort);
854 visited.addAll(arrayVisited[0]);
855 first.addAll(arrayVisited[0]);
856 last.addAll(arrayVisited[1]);
857 }
858 }
859 }
860 last.add(source);
861 arrayVisited[0] = first;
862 arrayVisited[1] = last;
863 return arrayVisited;
864 }
865
866
867
868
869
870
871
872 private ArrayList<Node<N>>[] depthFirstSearch() {
873 TreeSet<Node<N>> visited = new TreeSet<Node<N>>();
874 ArrayList<Node<N>>[] arrayVisited = new ArrayList[2];
875 ArrayList<Node<N>> first = new ArrayList<Node<N>>();
876 ArrayList<Node<N>> last = new ArrayList<Node<N>>();
877 for (Node<N> node : this.nodes) {
878 if (!visited.contains(node)) {
879 arrayVisited = this.depthFirstSearch(node, visited, null);
880 visited.addAll(arrayVisited[0]);
881 first.addAll(arrayVisited[0]);
882 last.addAll(arrayVisited[1]);
883 }
884 }
885 arrayVisited[0] = first;
886 arrayVisited[1] = last;
887 return arrayVisited;
888 }
889
890
891
892
893
894
895
896 private class Edges<N, E> extends AbstractSet<Edge<N, E>> implements SortedSet<Edge<N, E>> {
897
898
899
900
901 private final ConcreteDGraph<N, E> graph;
902
903
904
905
906
907
908 Edges(final ConcreteDGraph<N, E> graph) {
909 this.graph = graph;
910 }
911
912
913
914
915
916
917 protected final ConcreteDGraph<N, E> getGraph() {
918 return this.graph;
919 }
920
921
922
923
924
925
926 public final Edge<N, E> first() {
927 throw new UnsupportedOperationException();
928 }
929
930
931
932
933
934
935 public final Edge<N, E> last() {
936 throw new UnsupportedOperationException();
937 }
938
939
940
941
942
943
944
945
946
947
948 public final SortedSet<Edge<N, E>> headSet(final Edge<N, E> edge) {
949 throw new UnsupportedOperationException();
950 }
951
952
953
954
955
956
957
958
959
960
961 public final SortedSet<Edge<N, E>> tailSet(final Edge<N, E> edge) {
962 throw new UnsupportedOperationException();
963 }
964
965
966
967
968
969
970
971
972
973
974
975 public final SortedSet<Edge<N, E>> subSet(final Edge<N, E> fromEdge, final Edge<N, E> toEdge) {
976 throw new UnsupportedOperationException();
977 }
978
979
980
981
982
983
984 public final Comparator<? super Edge<N, E>> comparator() {
985 return null;
986 }
987
988
989
990
991
992
993 public final int size() {
994 return this.graph.sizeEdges();
995 }
996
997
998
999
1000
1001
1002 public final EdgesIterator iterator() {
1003 return new EdgesIterator(this);
1004 }
1005
1006
1007
1008
1009 private class EdgesIterator implements Iterator<Edge<N, E>> {
1010
1011
1012
1013
1014 private final Iterator<Node<N>> nodesIterator;
1015
1016
1017
1018
1019 private Iterator<Edge<N, E>> edgesIterator;
1020
1021
1022
1023
1024 private final Edges<N, E> edges;
1025
1026
1027
1028
1029 private boolean hasNext;
1030
1031
1032
1033
1034
1035
1036 EdgesIterator(final Edges<N, E> edges) {
1037 this.edges = edges;
1038 this.nodesIterator = edges.graph.nodes.iterator();
1039 this.prepareNext();
1040 }
1041
1042
1043
1044
1045 private void prepareNext() {
1046 this.hasNext = false;
1047 while (!this.hasNext && this.nodesIterator.hasNext()) {
1048 this.edgesIterator = this.edges.getGraph().successors.get(this.nodesIterator.next()).iterator();
1049 this.hasNext = this.edgesIterator.hasNext();
1050 }
1051 }
1052
1053
1054
1055
1056
1057
1058 @Override
1059 public void remove() {
1060 throw new UnsupportedOperationException();
1061 }
1062
1063
1064
1065
1066
1067
1068 public Edge<N, E> next() {
1069 Edge<N, E> edge = this.edgesIterator.next();
1070 if (!this.edgesIterator.hasNext()) {
1071 this.prepareNext();
1072 }
1073 return edge;
1074 }
1075
1076
1077
1078
1079
1080
1081 public boolean hasNext() {
1082 return this.hasNext;
1083 }
1084 }
1085 }
1086 }