1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.dishevelled.venn.tools;
25
26 import java.io.BufferedWriter;
27 import java.io.File;
28 import java.io.FileWriter;
29 import java.io.IOException;
30 import java.io.OutputStreamWriter;
31 import java.io.PrintWriter;
32
33 import java.util.ArrayList;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Set;
38
39 import com.google.common.collect.ImmutableMap;
40 import com.google.common.collect.ImmutableSet;
41 import com.google.common.collect.Sets;
42
43 import org.dishevelled.bitset.MutableBitSet;
44 import org.dishevelled.bitset.ImmutableBitSet;
45
46 import org.dishevelled.commandline.ArgumentList;
47 import org.dishevelled.commandline.CommandLine;
48 import org.dishevelled.commandline.CommandLineParseException;
49 import org.dishevelled.commandline.CommandLineParser;
50 import org.dishevelled.commandline.Switch;
51 import org.dishevelled.commandline.Usage;
52
53 import org.dishevelled.commandline.argument.FileArgument;
54
55 import org.dishevelled.venn.VennModel;
56
57 import org.dishevelled.venn.model.VennModels;
58
59
60
61
62
63
64 public final class Venn
65 extends AbstractVennRunnable
66 {
67
68 private final List<File> inputFiles;
69
70
71 private static final String USAGE = "java Venn [args] [input-files]";
72
73
74
75
76
77
78
79
80
81
82 private Venn(final boolean count, final boolean header, final List<File> inputFiles)
83 {
84 super(count, header);
85
86 if (inputFiles == null)
87 {
88 throw new IllegalArgumentException("inputFiles must not be null");
89 }
90 if (inputFiles.size() < 2)
91 {
92 throw new IllegalArgumentException("inputFiles must contain at least two input files");
93 }
94 if (inputFiles.size() > 29)
95 {
96 throw new IllegalArgumentException("inputFiles must contain less than 30 input files");
97 }
98 this.inputFiles = inputFiles;
99 }
100
101
102
103 public void run()
104 {
105 int n = inputFiles.size();
106 List<String> labels = new ArrayList<String>(n);
107 List<Set<String>> sets = new ArrayList<Set<String>>(n);
108 for (File inputFile : inputFiles)
109 {
110 labels.add(inputFile.getName());
111 sets.add(read(inputFile));
112 }
113 VennModel<String> model = VennModels.createVennModel(sets);
114
115 ImmutableMap.Builder<ImmutableBitSet, Set<String>> builder = ImmutableMap.builder();
116 Set<Set<Integer>> powerSet = Sets.powerSet(range(n));
117 for (Set<Integer> set : powerSet)
118 {
119 if (!set.isEmpty())
120 {
121 ImmutableBitSet key = toImmutableBitSet(set);
122 builder.put(key, model.exclusiveTo(first(key), additional(key)));
123 }
124 }
125 Map<ImmutableBitSet, Set<String>> views = builder.build();
126
127 PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
128 if (header())
129 {
130 for (Map.Entry<ImmutableBitSet, Set<String>> entry : views.entrySet())
131 {
132 write(true, buildLabel(labels, entry.getKey()), writer);
133 }
134
135 writer.print("\n");
136 }
137
138 if (count())
139 {
140 for (Map.Entry<ImmutableBitSet, Set<String>> entry : views.entrySet())
141 {
142 write(true, entry.getValue().size(), writer);
143 }
144
145 writer.print("\n");
146 }
147 else
148 {
149 List<Iterator<String>> iterators = new ArrayList<Iterator<String>>();
150
151 for (Map.Entry<ImmutableBitSet, Set<String>> entry : views.entrySet())
152 {
153 iterators.add(entry.getValue().iterator());
154 }
155
156 boolean done = false;
157 while (!done)
158 {
159 boolean left = false;
160 for (Iterator<String> iterator : iterators)
161 {
162 if (iterator.hasNext())
163 {
164 writer.write(iterator.next());
165 left = true;
166 }
167 writer.write("\t");
168 }
169
170 writer.print("\n");
171 done = !left;
172 }
173 }
174 try
175 {
176 writer.close();
177 }
178 catch (Exception e)
179 {
180
181 }
182 }
183
184
185
186 static String buildLabel(final List<String> labels, final ImmutableBitSet key)
187 {
188 int first = first(key);
189 int[] additional = additional(key);
190 StringBuilder sb = new StringBuilder();
191 sb.append(labels.get(first));
192 if (additional.length > 0) {
193 for (int i = 0, size = additional.length - 1; i < size; i++)
194 {
195 sb.append(", ");
196 sb.append(labels.get(additional[i]));
197 }
198 sb.append(" and ");
199 sb.append(labels.get(additional[Math.max(0, additional.length - 1)]));
200 }
201 sb.append(" only");
202 return sb.toString();
203 }
204
205 static ImmutableSet<Integer> range(final int n)
206 {
207 Set<Integer> range = Sets.newHashSet();
208 for (int i = 0; i < n; i++)
209 {
210 range.add(Integer.valueOf(i));
211 }
212 return ImmutableSet.copyOf(range);
213 }
214
215 static int first(final ImmutableBitSet bitSet)
216 {
217 return (int) bitSet.nextSetBit(0L);
218 }
219
220 static int[] additional(final ImmutableBitSet bitSet)
221 {
222 int[] additional = new int[Math.max(0, (int) bitSet.cardinality() - 1)];
223 int index = 0;
224 long first = bitSet.nextSetBit(0);
225 for (long value = bitSet.nextSetBit(first + 1); value >= 0L; value = bitSet.nextSetBit(value + 1))
226 {
227 additional[index] = (int) value;
228 index++;
229 }
230 return additional;
231 }
232
233 static int first(final Set<Integer> values)
234 {
235 if (values.isEmpty())
236 {
237 return -1;
238 }
239 return values.iterator().next().intValue();
240 }
241
242 static int[] additional(final Set<Integer> values)
243 {
244 int[] additional = new int[Math.max(0, values.size() - 1)];
245 int index = -1;
246 for (Integer value : values)
247 {
248 if (index >= 0)
249 {
250 additional[index] = value.intValue();
251 }
252 index++;
253 }
254 return additional;
255 }
256
257 static ImmutableBitSet toImmutableBitSet(final Set<Integer> indices)
258 {
259 if (indices == null)
260 {
261 throw new IllegalArgumentException("indices must not be null");
262 }
263 if (indices.isEmpty())
264 {
265 throw new IllegalArgumentException("indices must not be empty");
266 }
267 MutableBitSet mutableBitSet = new MutableBitSet(indices.size());
268 for (Integer index : indices)
269 {
270 mutableBitSet.set(index);
271 }
272 mutableBitSet.trimTrailingZeros();
273 return mutableBitSet.immutableCopy();
274 }
275
276
277
278
279
280
281 public static void main(final String[] args)
282 {
283 CommandLine commandLine = null;
284 ArgumentList arguments = null;
285 try
286 {
287 Switch help = new Switch("h", "help", "display help message");
288 Switch count = new Switch("c", "count", "output count(s) only");
289 Switch header = new Switch("e", "header", "output header(s)");
290
291 arguments = new ArgumentList(help, count, header);
292 commandLine = new CommandLine(args);
293 CommandLineParser.parse(commandLine, arguments);
294
295 if (help.wasFound())
296 {
297 Usage.usage(USAGE, null, commandLine, arguments, System.out);
298 }
299 else
300 {
301 List<File> inputFiles = new ArrayList<File>(args.length);
302 for (int i = 0; i < args.length; i++)
303 {
304
305 if (!args[i].startsWith("-"))
306 {
307 inputFiles.add(new File(args[i]));
308 }
309 }
310 new Venn(count.wasFound(), header.wasFound(), inputFiles).run();
311 }
312 }
313 catch (CommandLineParseException e)
314 {
315 Usage.usage(USAGE, e, commandLine, arguments, System.err);
316 }
317 catch (IllegalArgumentException e)
318 {
319 Usage.usage(USAGE, e, commandLine, arguments, System.err);
320 }
321 }
322 }