static O analyzeBitMap_idToText; // func(long) -> S // Looks only at the values static void analyzeBitMap(MultiMap bitMap) { analyzeBitMap(values(bitMap.data)); } static void analyzeBitMap(Collection> bitMap) { if (bitMap.isEmpty()) ret; new HashSet allSeen; for (L l : bitMap) allSeen.addAll(l); printStruct(+allSeen); MultiMap implies = fullSelfMap(allSeen); MultiMap eq = fullSelfMap(allSeen); for (L l : bitMap) { HashSet set = new HashSet(l); for (Long a : cloneList(implies.keySet())) { bool ax = set.contains(a); for (Long b : cloneList(implies.get(a))) { bool bx = set.contains(b); if (ax && !bx) implies.remove(a, b); } } for (Long a : cloneList(eq.keySet())) { bool ax = set.contains(a); for (Long b : cloneList(eq.get(a))) { bool bx = set.contains(b); if (ax != bx) eq.remove(a, b); } } } printStruct(+implies); //printStruct(+eq); L> clusters = multiMapToClusters(eq); for i over clusters: print("Cluster \* i+1 */: " + struct(mapIfFunctionNotNull(analyzeBitMap_idToText, clusters.get(i)))); } static MultiMap fullSelfMap(Collection l) { new MultiMap mm; for (Long x : l) mm.putAll(x, l); ret mm; } static L> multiMapToClusters(MultiMap mm) { // a cluster is a list of concepts. // first, make trivial clusters (one per item). Map> clusters = new TreeMap>(); for (Long a : mm.keySet()) { if (!clusters.containsKey(a)) clusters.put(a, ll(a)); } // then, merge the clusters. for (Long a : mm.keySet()) for (Long b : mm.get(a)) { L c1 = clusters.get(a); L c2 = clusters.get(b); if (c1 != c2) // different clusters, need to merge! mergeClusters(clusters, c1, c2); } ret asList(new HashSet>(clusters.values())); } static void mergeClusters(Map> clusters, L c1, L c2) { for (Long x : c2) { clusters.put(x, c1); c1.add(x); } }