001 package org.expasy.jpl.commons.collection.graph;
002
003
004 import java.io.PrintStream;
005 import java.util.ArrayList;
006 import java.util.Collection;
007 import java.util.Collections;
008 import java.util.Comparator;
009 import java.util.List;
010 import org.apache.commons.collections15.Predicate;
011 import org.apache.commons.collections15.Transformer;
012 import org.expasy.jpl.commons.base.builder.BuilderException;
013 import org.expasy.jpl.commons.base.builder.InstanceBuilder;
014 import edu.uci.ics.jung.graph.Graph;
015 import edu.uci.ics.jung.graph.util.Pair;
016
017
018 /**
019 * This object exports graphs.
020 *
021 * @author nikitin
022 *
023 * @version 1.0
024 *
025 */
026 public final class GraphExporter<V, E> {
027
028 private static final ObjectComparator UNIVERSAL_COMPARATOR =
029 new ObjectComparator();
030 private Transformer<E, String> edgeValueTransformer;
031
032 private PrintStream ps;
033 private List<Predicate<V>> predicateFilters;
034
035 private GraphExporter(Builder<V, E> builder) {
036 ps = builder.ps;
037 edgeValueTransformer = builder.edgeValueTransformer;
038 predicateFilters = builder.predicates;
039 }
040
041 public static class Builder<V, E> implements
042 InstanceBuilder<GraphExporter<V, E>> {
043
044 private PrintStream ps;
045 private List<Predicate<V>> predicates;
046 private Transformer<E, String> edgeValueTransformer =
047 new Transformer<E, String>() {
048
049 @Override
050 public String transform(E edge) {
051 return edge.toString();
052 }
053
054 };
055
056 public Builder() {
057 ps = System.out;
058 predicates = new ArrayList<Predicate<V>>();
059 }
060
061 public Builder<V, E> printStream(PrintStream ps) {
062 this.ps = ps;
063 return this;
064 }
065
066 public Builder<V, E> predicate(Predicate<V> predicate) {
067 predicates.add(predicate);
068 return this;
069 }
070
071 public Builder<V, E> edgeValueTransformer(
072 Transformer<E, String> transformer) {
073 edgeValueTransformer = transformer;
074 return this;
075 }
076
077 @Override
078 public GraphExporter<V, E> build() throws BuilderException {
079 return new GraphExporter<V, E>(this);
080 }
081
082 }
083
084 public static <V, E> GraphExporter<V, E> newInstance() {
085 return new GraphExporter.Builder<V, E>().build();
086 }
087
088 public String export(Graph<V, E> graph,
089 Transformer<Graph<V, E>, String> transformer) {
090
091 return transformer.transform(graph);
092 }
093
094 public void exportKPGraph(KPartiteGraphImpl<V, E> g) {
095 // all predicates by default
096 Collection<Predicate<V>> preds = g.getPartitions();
097
098 ps.print("KPGraph " + g.getId() + "\n");
099 ps.print(" |-- Vertices (x");
100
101 // filter on predicates
102 if (predicateFilters != null && predicateFilters.size() > 0) {
103 preds = predicateFilters;
104 ps.print(g.getVertexCount(preds));
105 } else {
106 ps.print(g.getVertexCount());
107 }
108 ps.print(")\n");
109
110 int count = 0;
111 Predicate<V> lastPredicate = null;
112 List<V> nodes;
113 for (Predicate<V> predicate : preds) {
114 if (count == preds.size() - 1) {
115 lastPredicate = predicate;
116 break;
117 }
118
119 nodes = new ArrayList<V>(g.getVertices(predicate));
120
121 ps.print(" | |-- predicate-" + count);
122 ps.print(" (x" + nodes.size() + ")\n");
123
124 if (nodes.size() > 0) {
125 Collections.sort(nodes, UNIVERSAL_COMPARATOR);
126
127 for (int i = 0; i < nodes.size() - 1; i++) {
128 ps.print(" | | |-- ");
129 ps.print(nodes.get(i));
130 ps.print("\n");
131 }
132 // last vertex
133 ps.print(" | | `-- ");
134 ps.print(nodes.get(nodes.size() - 1));
135 ps.print("\n");
136 }
137 count++;
138 }
139 // last predicate
140 nodes = new ArrayList<V>(g.getVertices(lastPredicate));
141
142 ps.print(" | `-- predicate-" + count);
143 ps.print(" (x" + nodes.size() + ")\n");
144
145 if (nodes.size() > 0) {
146 Collections.sort(nodes, UNIVERSAL_COMPARATOR);
147 for (int i = 0; i < nodes.size() - 1; i++) {
148 ps.print(" | |-- ");
149 ps.print(nodes.get(i));
150 ps.print("\n");
151 }
152 // last vertex
153 ps.print(" | `-- ");
154 ps.print(nodes.get(nodes.size() - 1));
155 ps.print("\n");
156 }
157
158 ps.print(" `-- Edges (x");
159
160 // filter on predicates
161 if (predicateFilters != null && predicateFilters.size() > 0) {
162 ps.print(g.getEdgeCount(preds));
163 } else {
164 ps.print(g.getEdgeCount());
165 }
166 ps.print(")\n");
167
168 count = 0;
169
170 Pair<V> pair = null;
171 E lastEdge = null;
172 List<E> es = new ArrayList<E>();
173
174 if (predicateFilters != null && predicateFilters.size() > 0) {
175 es.addAll(g.getEdges(predicateFilters));
176 } else {
177 es.addAll(g.getEdges());
178 }
179 Collections.sort(es, UNIVERSAL_COMPARATOR);
180 String edgeValueString = null;
181 for (E edge : es) {
182 pair = g.getEndpoints(edge);
183
184 if (count == es.size() - 1) {
185 lastEdge = edge;
186 break;
187 }
188
189 ps.print(" |-- " + pair.getFirst() + " <--> "
190 + pair.getSecond());
191
192 edgeValueString = edgeValueTransformer.transform(edge);
193
194 if (edgeValueString != null) {
195 ps.print(" (" + edgeValueString + ")");
196 }
197 ps.print("\n");
198
199 count++;
200 }
201 // write last edge
202 ps.print(" `-- " + pair.getFirst() + " <--> " + pair.getSecond());
203
204 edgeValueString = edgeValueTransformer.transform(lastEdge);
205
206 if (edgeValueString != null) {
207 ps.print(" (" + edgeValueString + ")");
208 }
209 ps.print("\n");
210
211 ps.close();
212 }
213
214 /**
215 * @return a copy of the given undirected sparse graph.
216 */
217 public static class DotTransformer<V, E> implements
218 Transformer<Graph<V, E>, String> {
219
220 @Override
221 public String transform(Graph<V, E> graph) {
222 final StringBuilder sb = new StringBuilder();
223
224 sb.append("graph G {\n");
225 for (final V vertex : graph.getVertices()) {
226 sb.append(vertex + ";\n");
227 }
228 for (final E edge : graph.getEdges()) {
229 sb.append(edge + ";\n");
230 }
231 sb.append("}\n");
232
233 return sb.toString();
234 }
235
236 }
237
238 public static class ObjectComparator implements Comparator<Object> {
239
240 @Override
241 public int compare(Object o1, Object o2) {
242 return o1.toString().compareTo(o2.toString());
243 }
244
245 }
246 }