| 1 | package weka.clusterers.forMetisMQI; |
|---|
| 2 | |
|---|
| 3 | import java.util.ArrayList; |
|---|
| 4 | import java.util.BitSet; |
|---|
| 5 | import java.util.HashMap; |
|---|
| 6 | import java.util.Iterator; |
|---|
| 7 | import java.util.List; |
|---|
| 8 | import java.util.SortedSet; |
|---|
| 9 | import java.util.TreeSet; |
|---|
| 10 | import java.util.Map.Entry; |
|---|
| 11 | |
|---|
| 12 | public class Subgraph { |
|---|
| 13 | |
|---|
| 14 | private Graph g = null; |
|---|
| 15 | private BitSet nodes = null; |
|---|
| 16 | private List<Integer> listOfNodes = null; |
|---|
| 17 | private HashMap<Integer,Integer> ID = null; |
|---|
| 18 | private HashMap<Integer,Integer> ED = null; |
|---|
| 19 | private HashMap<Integer,List<Integer>> bucketGain = null; |
|---|
| 20 | private SortedSet<Integer> gainSet = null; |
|---|
| 21 | private boolean recomputeGain = true; |
|---|
| 22 | |
|---|
| 23 | public Subgraph(Graph g){ |
|---|
| 24 | this.g = g; |
|---|
| 25 | nodes = new BitSet(g.size()); |
|---|
| 26 | listOfNodes = new ArrayList<Integer>(); |
|---|
| 27 | ID = new HashMap<Integer,Integer>(); |
|---|
| 28 | ED = new HashMap<Integer,Integer>(); |
|---|
| 29 | bucketGain = new HashMap<Integer, List<Integer>>(); |
|---|
| 30 | gainSet = new TreeSet<Integer>(); |
|---|
| 31 | } |
|---|
| 32 | |
|---|
| 33 | public Graph getGraph() { |
|---|
| 34 | return g; |
|---|
| 35 | } |
|---|
| 36 | |
|---|
| 37 | public void addNode(int u) { |
|---|
| 38 | nodes.set(g.getIndex(u)); |
|---|
| 39 | listOfNodes.add(u); |
|---|
| 40 | ID.put(u, 0); |
|---|
| 41 | ED.put(u, 0); |
|---|
| 42 | recomputeGain = true; |
|---|
| 43 | } |
|---|
| 44 | |
|---|
| 45 | private void computeDegree() { |
|---|
| 46 | for(int i = 0; i < size(); i++) { |
|---|
| 47 | int u = listOfNodes.get(i); |
|---|
| 48 | Iterator<Integer> it = g.getNeighbors(u).iterator(); |
|---|
| 49 | int newID = 0; |
|---|
| 50 | int newED = 0; |
|---|
| 51 | while(it.hasNext()) { |
|---|
| 52 | int v = it.next(); |
|---|
| 53 | if(contains(v)) |
|---|
| 54 | newID = newID + g.getWeight(u, v); |
|---|
| 55 | else |
|---|
| 56 | newED = newED + g.getWeight(u, v); |
|---|
| 57 | ID.put(u, newID); |
|---|
| 58 | ED.put(u, newED); |
|---|
| 59 | } |
|---|
| 60 | } |
|---|
| 61 | } |
|---|
| 62 | |
|---|
| 63 | private void computeGain() { |
|---|
| 64 | bucketGain.clear(); |
|---|
| 65 | gainSet.clear(); |
|---|
| 66 | ID.clear(); |
|---|
| 67 | ED.clear(); |
|---|
| 68 | computeDegree(); |
|---|
| 69 | for(int i = 0; i < size(); i++) { |
|---|
| 70 | int u = listOfNodes.get(i); |
|---|
| 71 | int gainU = ED.get(u) - ID.get(u); |
|---|
| 72 | if(!bucketGain.containsKey(gainU)) { |
|---|
| 73 | bucketGain.put(gainU, new ArrayList<Integer>()); |
|---|
| 74 | } |
|---|
| 75 | bucketGain.get(gainU).add(u); |
|---|
| 76 | gainSet.add(gainU); |
|---|
| 77 | } |
|---|
| 78 | recomputeGain = false; |
|---|
| 79 | } |
|---|
| 80 | |
|---|
| 81 | public int getCandidate() { |
|---|
| 82 | return getCandidate(new ArrayList<Integer>()); |
|---|
| 83 | } |
|---|
| 84 | |
|---|
| 85 | /** |
|---|
| 86 | * |
|---|
| 87 | * @param marked |
|---|
| 88 | * @return the candidate node for swap or -1 if there aren't available nodes. |
|---|
| 89 | */ |
|---|
| 90 | public int getCandidate(List<Integer> marked) { |
|---|
| 91 | if(recomputeGain) |
|---|
| 92 | computeGain(); |
|---|
| 93 | int candidate = -1; |
|---|
| 94 | Iterator<Integer> iterator = ((TreeSet<Integer>)gainSet).descendingIterator(); |
|---|
| 95 | while(iterator.hasNext() && (candidate == -1)) { |
|---|
| 96 | int gain = iterator.next(); |
|---|
| 97 | Iterator<Integer> nodes = bucketGain.get(gain).iterator(); |
|---|
| 98 | while(nodes.hasNext() && (candidate == -1)) { |
|---|
| 99 | int u = nodes.next(); |
|---|
| 100 | if(!marked.contains(u)) |
|---|
| 101 | candidate = u; |
|---|
| 102 | } |
|---|
| 103 | } |
|---|
| 104 | return candidate; |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | public int gain(int u){ |
|---|
| 108 | if(recomputeGain) |
|---|
| 109 | computeGain(); |
|---|
| 110 | return ED.get(u) - ID.get(u); |
|---|
| 111 | } |
|---|
| 112 | |
|---|
| 113 | public void remove(int u) { |
|---|
| 114 | if(recomputeGain) |
|---|
| 115 | computeGain(); |
|---|
| 116 | int gainU = gain(u); |
|---|
| 117 | nodes.set(g.getIndex(u), false); |
|---|
| 118 | listOfNodes.remove(listOfNodes.indexOf(u)); |
|---|
| 119 | ID.remove(u); |
|---|
| 120 | ED.remove(u); |
|---|
| 121 | List<Integer> l = bucketGain.get(gainU); |
|---|
| 122 | l.remove(l.indexOf(u)); |
|---|
| 123 | if(l.size() == 0) { |
|---|
| 124 | bucketGain.remove(gainU); |
|---|
| 125 | gainSet.remove(gainU); |
|---|
| 126 | } |
|---|
| 127 | recomputeGain = true; |
|---|
| 128 | } |
|---|
| 129 | |
|---|
| 130 | public int size() { |
|---|
| 131 | return listOfNodes.size(); |
|---|
| 132 | } |
|---|
| 133 | |
|---|
| 134 | public int getWeight(int u, int v) { |
|---|
| 135 | int ret = -1; |
|---|
| 136 | if(isEdge(u,v)) |
|---|
| 137 | ret = g.getWeight(u, v); |
|---|
| 138 | return ret; |
|---|
| 139 | } |
|---|
| 140 | |
|---|
| 141 | public Iterator<Integer> iterator() { |
|---|
| 142 | return listOfNodes.iterator(); |
|---|
| 143 | } |
|---|
| 144 | |
|---|
| 145 | public boolean isEdge(int u, int v) { |
|---|
| 146 | return nodes.get(g.getIndex(u)) && nodes.get(g.getIndex(v)) && g.isEdge(u, v); |
|---|
| 147 | } |
|---|
| 148 | |
|---|
| 149 | public boolean contains(int u) { |
|---|
| 150 | return nodes.get(g.getIndex(u)); |
|---|
| 151 | } |
|---|
| 152 | |
|---|
| 153 | public List<Integer> getNeighbours(int u) { |
|---|
| 154 | List<Integer> neighbors = new ArrayList<Integer>(); |
|---|
| 155 | Iterator<Integer> iterator = g.getNeighbors(u).iterator(); |
|---|
| 156 | while(iterator.hasNext()) { |
|---|
| 157 | int v = iterator.next(); |
|---|
| 158 | if(contains(v) && isEdge(u, v)) |
|---|
| 159 | neighbors.add(v); |
|---|
| 160 | } |
|---|
| 161 | return neighbors; |
|---|
| 162 | } |
|---|
| 163 | |
|---|
| 164 | public int getExternalDegree() { |
|---|
| 165 | if(recomputeGain) |
|---|
| 166 | computeGain(); |
|---|
| 167 | int acc = 0; |
|---|
| 168 | Iterator<Integer> it = ED.values().iterator(); |
|---|
| 169 | while(it.hasNext()) |
|---|
| 170 | acc = acc + it.next(); |
|---|
| 171 | return acc; |
|---|
| 172 | } |
|---|
| 173 | |
|---|
| 174 | @Override |
|---|
| 175 | public String toString() { |
|---|
| 176 | String out = "["; |
|---|
| 177 | Iterator<Integer> it = listOfNodes.iterator(); |
|---|
| 178 | while(it.hasNext()) { |
|---|
| 179 | int u = it.next(); |
|---|
| 180 | out = out + u + ","; |
|---|
| 181 | } |
|---|
| 182 | out = out + "]"; |
|---|
| 183 | return out; |
|---|
| 184 | } |
|---|
| 185 | |
|---|
| 186 | public List<Integer> getBoundary() { |
|---|
| 187 | if(recomputeGain) |
|---|
| 188 | computeGain(); |
|---|
| 189 | Iterator<Entry<Integer,Integer>> EDIterator = ED.entrySet().iterator(); |
|---|
| 190 | List<Integer> boundary = new ArrayList<Integer>(); |
|---|
| 191 | while(EDIterator.hasNext()) { |
|---|
| 192 | Entry<Integer,Integer> entry = EDIterator.next(); |
|---|
| 193 | if(entry.getValue() > 0) |
|---|
| 194 | boundary.add(entry.getKey()); |
|---|
| 195 | } |
|---|
| 196 | return boundary; |
|---|
| 197 | } |
|---|
| 198 | |
|---|
| 199 | private Subgraph() { |
|---|
| 200 | |
|---|
| 201 | } |
|---|
| 202 | |
|---|
| 203 | @Override |
|---|
| 204 | public Subgraph clone() { |
|---|
| 205 | Subgraph clone = new Subgraph(); |
|---|
| 206 | clone.g = g.clone(); |
|---|
| 207 | |
|---|
| 208 | clone.nodes = (BitSet)nodes.clone(); |
|---|
| 209 | |
|---|
| 210 | clone.listOfNodes = new ArrayList<Integer>(); |
|---|
| 211 | for(int i = 0; i < listOfNodes.size(); i++) { |
|---|
| 212 | clone.listOfNodes.add(listOfNodes.get(i)); |
|---|
| 213 | } |
|---|
| 214 | |
|---|
| 215 | clone.ID = new HashMap<Integer, Integer>(); |
|---|
| 216 | Iterator<Entry<Integer,Integer>> i = ID.entrySet().iterator(); |
|---|
| 217 | while(i.hasNext()) { |
|---|
| 218 | Entry<Integer,Integer> entry = i.next(); |
|---|
| 219 | clone.ID.put(entry.getKey(), entry.getValue()); |
|---|
| 220 | } |
|---|
| 221 | |
|---|
| 222 | clone.ED = new HashMap<Integer, Integer>(); |
|---|
| 223 | i = ED.entrySet().iterator(); |
|---|
| 224 | while(i.hasNext()) { |
|---|
| 225 | Entry<Integer,Integer> entry = i.next(); |
|---|
| 226 | clone.ED.put(entry.getKey(), entry.getValue()); |
|---|
| 227 | } |
|---|
| 228 | |
|---|
| 229 | clone.bucketGain = new HashMap<Integer, List<Integer>>(); |
|---|
| 230 | Iterator<Entry<Integer,List<Integer>>>it = bucketGain.entrySet().iterator(); |
|---|
| 231 | while(it.hasNext()) { |
|---|
| 232 | Entry<Integer,List<Integer>> entry = it.next(); |
|---|
| 233 | List<Integer> bucketClone = new ArrayList<Integer>(); |
|---|
| 234 | List<Integer> bucket = entry.getValue(); |
|---|
| 235 | for(int j = 0; j < bucket.size(); j++) { |
|---|
| 236 | bucketClone.add(bucket.get(j)); |
|---|
| 237 | } |
|---|
| 238 | clone.bucketGain.put(entry.getKey(), bucketClone); |
|---|
| 239 | } |
|---|
| 240 | |
|---|
| 241 | clone.gainSet = new TreeSet<Integer>(); |
|---|
| 242 | Iterator<Integer> gainIt = gainSet.iterator(); |
|---|
| 243 | while(gainIt.hasNext()) { |
|---|
| 244 | gainSet.add(gainIt.next()); |
|---|
| 245 | } |
|---|
| 246 | |
|---|
| 247 | clone.recomputeGain = recomputeGain; |
|---|
| 248 | |
|---|
| 249 | return clone; |
|---|
| 250 | } |
|---|
| 251 | } |
|---|