| 1 | package weka.clusterers.forMetisMQI; |
|---|
| 2 | |
|---|
| 3 | import java.io.PrintStream; |
|---|
| 4 | import java.util.ArrayList; |
|---|
| 5 | import java.util.HashMap; |
|---|
| 6 | import java.util.Iterator; |
|---|
| 7 | import java.util.List; |
|---|
| 8 | import java.util.Map.Entry; |
|---|
| 9 | |
|---|
| 10 | import weka.core.Attribute; |
|---|
| 11 | import weka.core.Instance; |
|---|
| 12 | import weka.core.Instances; |
|---|
| 13 | |
|---|
| 14 | public class Graph { |
|---|
| 15 | |
|---|
| 16 | protected static class NodeInfo { |
|---|
| 17 | /** The weight of the node */ |
|---|
| 18 | protected int vwgt; |
|---|
| 19 | /** The size of the adjacency list of the node */ |
|---|
| 20 | protected int nedges; |
|---|
| 21 | /** |
|---|
| 22 | * The index into the adjacency list that is the beginning of the |
|---|
| 23 | * adjacency list of v |
|---|
| 24 | */ |
|---|
| 25 | protected int iedges; |
|---|
| 26 | /** The weight of the edges that have been contracted to create the node */ |
|---|
| 27 | protected int cewgt; |
|---|
| 28 | /** The sum of the weight of the edges adjacent to v */ |
|---|
| 29 | protected int adjwgt; |
|---|
| 30 | |
|---|
| 31 | public NodeInfo() { |
|---|
| 32 | this.vwgt = 1; |
|---|
| 33 | this.cewgt = 0; |
|---|
| 34 | this.iedges = 0; |
|---|
| 35 | this.nedges = 0; |
|---|
| 36 | this.adjwgt = 0; |
|---|
| 37 | |
|---|
| 38 | } |
|---|
| 39 | |
|---|
| 40 | @Override |
|---|
| 41 | public String toString() { |
|---|
| 42 | return "Vwgt: " + vwgt + " Cewgt: " + cewgt + " Iedges: " + iedges |
|---|
| 43 | + " Nedges: " + nedges + " Adjwgt: " + adjwgt; |
|---|
| 44 | } |
|---|
| 45 | |
|---|
| 46 | @Override |
|---|
| 47 | public NodeInfo clone() { |
|---|
| 48 | NodeInfo ni = new NodeInfo(); |
|---|
| 49 | ni.adjwgt = adjwgt; |
|---|
| 50 | ni.cewgt = cewgt; |
|---|
| 51 | ni.iedges = iedges; |
|---|
| 52 | ni.nedges = nedges; |
|---|
| 53 | ni.vwgt = vwgt; |
|---|
| 54 | return ni; |
|---|
| 55 | } |
|---|
| 56 | } |
|---|
| 57 | |
|---|
| 58 | /** |
|---|
| 59 | * Additional node info for all vertices.. |
|---|
| 60 | */ |
|---|
| 61 | private List<NodeInfo> vtxs; |
|---|
| 62 | /** |
|---|
| 63 | * Adjacency vector. |
|---|
| 64 | */ |
|---|
| 65 | private List<Integer> adjncy; |
|---|
| 66 | /** |
|---|
| 67 | * Weights vector |
|---|
| 68 | */ |
|---|
| 69 | private List<Integer> weights; |
|---|
| 70 | |
|---|
| 71 | private HashMap<Integer,Integer> label; |
|---|
| 72 | private HashMap<Integer,Integer> index; |
|---|
| 73 | |
|---|
| 74 | /** |
|---|
| 75 | * Build a new graph given a set of instances. |
|---|
| 76 | * |
|---|
| 77 | * @param data |
|---|
| 78 | */ |
|---|
| 79 | public Graph(Instances data) { |
|---|
| 80 | vtxs = new ArrayList<NodeInfo>(); |
|---|
| 81 | adjncy = new ArrayList<Integer>(); |
|---|
| 82 | weights = new ArrayList<Integer>(); |
|---|
| 83 | label = new HashMap<Integer,Integer>(); |
|---|
| 84 | index = new HashMap<Integer,Integer>(); |
|---|
| 85 | Iterator<Instance> dataIterator = data.iterator(); |
|---|
| 86 | Attribute from = data.attribute("from"); |
|---|
| 87 | Attribute to = data.attribute("to"); |
|---|
| 88 | if (from == null || to == null) |
|---|
| 89 | throw new RuntimeException( |
|---|
| 90 | "Unsupported data: check the list of attributes (from and to are needed)."); |
|---|
| 91 | while (dataIterator.hasNext()) { |
|---|
| 92 | Instance edge = dataIterator.next(); |
|---|
| 93 | int node1 = (int) Math.round(edge.value(from)); |
|---|
| 94 | int node2 = (int) Math.round(edge.value(to)); |
|---|
| 95 | addNode(node1); addNode(node2); |
|---|
| 96 | addEdgeUndirected(node1, node2, 1); |
|---|
| 97 | } |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | public Graph() { |
|---|
| 101 | vtxs = new ArrayList<NodeInfo>(); |
|---|
| 102 | adjncy = new ArrayList<Integer>(); |
|---|
| 103 | weights = new ArrayList<Integer>(); |
|---|
| 104 | label = new HashMap<Integer,Integer>(); |
|---|
| 105 | index = new HashMap<Integer,Integer>(); |
|---|
| 106 | } |
|---|
| 107 | |
|---|
| 108 | /** |
|---|
| 109 | * Returns an iterator over the nodes of the graph. |
|---|
| 110 | * @return |
|---|
| 111 | */ |
|---|
| 112 | public Iterator<Integer> iterator() { |
|---|
| 113 | return label.keySet().iterator(); |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | /** |
|---|
| 117 | * Returns the label associated with a given index. |
|---|
| 118 | * @param index |
|---|
| 119 | * @return |
|---|
| 120 | */ |
|---|
| 121 | public int getLabel(int index) { |
|---|
| 122 | return this.index.get(index); |
|---|
| 123 | } |
|---|
| 124 | |
|---|
| 125 | /** |
|---|
| 126 | * Returns the index associated with a given label. |
|---|
| 127 | * @param index |
|---|
| 128 | * @return |
|---|
| 129 | */ |
|---|
| 130 | public int getIndex(int label) { |
|---|
| 131 | return this.label.get(label); |
|---|
| 132 | } |
|---|
| 133 | |
|---|
| 134 | private void updateAssociation(int index, int label) { |
|---|
| 135 | this.index.put(index,label); |
|---|
| 136 | this.label.put(label,index); |
|---|
| 137 | } |
|---|
| 138 | |
|---|
| 139 | /** |
|---|
| 140 | * Returns the weight of the edge (u,v). |
|---|
| 141 | * @param u |
|---|
| 142 | * @param v |
|---|
| 143 | * @return |
|---|
| 144 | */ |
|---|
| 145 | public int getWeight(int u, int v) { |
|---|
| 146 | int i = getIndex(u); |
|---|
| 147 | int istart = vtxs.get(i).iedges; |
|---|
| 148 | int iend = vtxs.get(i).iedges + vtxs.get(i).nedges; |
|---|
| 149 | int weight = -1; boolean found = false; |
|---|
| 150 | for(int k = istart; k < iend && !found; k++) { |
|---|
| 151 | if(adjncy.get(k) == v) { |
|---|
| 152 | weight = weights.get(k); |
|---|
| 153 | found = true; |
|---|
| 154 | } |
|---|
| 155 | } |
|---|
| 156 | return weight; |
|---|
| 157 | } |
|---|
| 158 | |
|---|
| 159 | public void setWeight(int u, int v, int weight) { |
|---|
| 160 | int i = getIndex(u); |
|---|
| 161 | int j = getIndex(v); |
|---|
| 162 | int istart = vtxs.get(i).iedges; |
|---|
| 163 | int iend = istart + vtxs.get(i).nedges; |
|---|
| 164 | for(int k = istart; k < iend; k++){ |
|---|
| 165 | if(adjncy.get(k) == v) { |
|---|
| 166 | weights.set(k, weight); |
|---|
| 167 | } |
|---|
| 168 | } |
|---|
| 169 | int jstart = vtxs.get(j).iedges; |
|---|
| 170 | int jend = jstart + vtxs.get(j).nedges; |
|---|
| 171 | for(int k = jstart; k < jend; k++){ |
|---|
| 172 | if(adjncy.get(k) == u) |
|---|
| 173 | weights.set(k, weight); |
|---|
| 174 | } |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | public NodeInfo getNode(int u) { |
|---|
| 178 | int i = getIndex(u); |
|---|
| 179 | return vtxs.get(i); |
|---|
| 180 | } |
|---|
| 181 | |
|---|
| 182 | public int nedge() { |
|---|
| 183 | return adjncy.size(); |
|---|
| 184 | } |
|---|
| 185 | |
|---|
| 186 | public boolean isNode(int u) { |
|---|
| 187 | return label.containsKey(u); |
|---|
| 188 | } |
|---|
| 189 | |
|---|
| 190 | public void addNode(int u) { |
|---|
| 191 | if(!isNode(u)) { |
|---|
| 192 | int index = size(); |
|---|
| 193 | updateAssociation(index, u); |
|---|
| 194 | NodeInfo node = new NodeInfo(); |
|---|
| 195 | node.iedges = nedge(); |
|---|
| 196 | node.nedges = 0; |
|---|
| 197 | node.vwgt = 1; |
|---|
| 198 | node.adjwgt = 0; |
|---|
| 199 | node.cewgt = 0; |
|---|
| 200 | vtxs.add(index, node); |
|---|
| 201 | } |
|---|
| 202 | } |
|---|
| 203 | |
|---|
| 204 | public int size() { |
|---|
| 205 | return vtxs.size(); |
|---|
| 206 | } |
|---|
| 207 | |
|---|
| 208 | public List<Integer> getNeighbors(int u) { |
|---|
| 209 | int i = getIndex(u); |
|---|
| 210 | List<Integer> neighbors = new ArrayList<Integer>(); |
|---|
| 211 | int istart = vtxs.get(i).iedges; |
|---|
| 212 | int iend = vtxs.get(i).iedges + vtxs.get(i).nedges; |
|---|
| 213 | for(int k = istart; k < iend; k++) { |
|---|
| 214 | neighbors.add(adjncy.get(k)); |
|---|
| 215 | } |
|---|
| 216 | return neighbors; |
|---|
| 217 | } |
|---|
| 218 | |
|---|
| 219 | /** |
|---|
| 220 | * Return true if u is neighbor of v. |
|---|
| 221 | * @param u |
|---|
| 222 | * @param v |
|---|
| 223 | * @return |
|---|
| 224 | */ |
|---|
| 225 | public boolean isNeighbor(int u, int v){ |
|---|
| 226 | return getNeighbors(u).contains(v); |
|---|
| 227 | } |
|---|
| 228 | |
|---|
| 229 | public void addEdgeUndirected(int i, int j, int w) { |
|---|
| 230 | addEdgeDirectedl(i, j, w); |
|---|
| 231 | addEdgeDirectedl(j, i, w); |
|---|
| 232 | } |
|---|
| 233 | |
|---|
| 234 | /** |
|---|
| 235 | * Add an edge from i to j of weight w if previously it doesn't exists, otherwise |
|---|
| 236 | * simply update the weight of the edge. |
|---|
| 237 | * @param i |
|---|
| 238 | * @param j |
|---|
| 239 | * @param w |
|---|
| 240 | */ |
|---|
| 241 | public void addEdgeDirectedl(int u, int v, int w) { |
|---|
| 242 | int i = getIndex(u); |
|---|
| 243 | if(!isNeighbor(u,v)) { |
|---|
| 244 | int istart = getNode(u).iedges; |
|---|
| 245 | adjncy.add(istart,v); |
|---|
| 246 | for(int k = i + 1; k < size(); k++) { |
|---|
| 247 | vtxs.get(k).iedges++; |
|---|
| 248 | } |
|---|
| 249 | vtxs.get(i).nedges++; |
|---|
| 250 | vtxs.get(i).adjwgt += w; |
|---|
| 251 | weights.add(istart, w); |
|---|
| 252 | } else |
|---|
| 253 | setWeight(u, v, w); |
|---|
| 254 | } |
|---|
| 255 | |
|---|
| 256 | public boolean isEdge(int u, int v) { |
|---|
| 257 | int i = getIndex(u); |
|---|
| 258 | int istart = vtxs.get(i).iedges; |
|---|
| 259 | int iend = vtxs.get(i).iedges + vtxs.get(i).nedges; |
|---|
| 260 | boolean found = false; |
|---|
| 261 | for(int k = istart; k < iend && !found; k++) { |
|---|
| 262 | found = (adjncy.get(k) == v); |
|---|
| 263 | } |
|---|
| 264 | return found; |
|---|
| 265 | } |
|---|
| 266 | |
|---|
| 267 | /** |
|---|
| 268 | * Print the graph structure. |
|---|
| 269 | */ |
|---|
| 270 | public void printGraph(PrintStream io) { |
|---|
| 271 | for(int i = 0; i < vtxs.size(); i++) { |
|---|
| 272 | int u = getLabel(i); |
|---|
| 273 | io.print("Node: " + u + " Neighbors: "); |
|---|
| 274 | Iterator<Integer> neighbors = getNeighbors(u).iterator(); |
|---|
| 275 | while(neighbors.hasNext()) { |
|---|
| 276 | int v = neighbors.next(); |
|---|
| 277 | io.print(v + " [w: " + getWeight(u, v) + "] "); |
|---|
| 278 | } |
|---|
| 279 | io.println(getNode(u).toString()); |
|---|
| 280 | } |
|---|
| 281 | } |
|---|
| 282 | |
|---|
| 283 | /** |
|---|
| 284 | * Return a list containing a random permutation of the vertices. |
|---|
| 285 | * |
|---|
| 286 | * @return a random permutation of vertices |
|---|
| 287 | */ |
|---|
| 288 | public List<Integer> vtxsPermutation() { |
|---|
| 289 | Random r = Random.instance(); |
|---|
| 290 | List<Integer> perm = new ArrayList<Integer>(); |
|---|
| 291 | for (int i = 0; i < vtxs.size(); i++) { |
|---|
| 292 | perm.add(getLabel(i)); |
|---|
| 293 | } |
|---|
| 294 | for (int i = 0; i < perm.size(); i++) { |
|---|
| 295 | int k = r.nextInt(perm.size()); |
|---|
| 296 | int swap = perm.get(k); |
|---|
| 297 | perm.set(k, perm.get(i)); |
|---|
| 298 | perm.set(i, swap); |
|---|
| 299 | } |
|---|
| 300 | return perm; |
|---|
| 301 | } |
|---|
| 302 | |
|---|
| 303 | /** |
|---|
| 304 | * Randomize the adjacency list. |
|---|
| 305 | */ |
|---|
| 306 | public void adjncyPermutation() { |
|---|
| 307 | Random r = Random.instance(); |
|---|
| 308 | for (int i = 0; i < vtxs.size(); i++) { |
|---|
| 309 | NodeInfo n = vtxs.get(i); |
|---|
| 310 | for (int j = n.iedges; j < n.nedges + n.iedges; j++) { |
|---|
| 311 | int k = r.nextInt(n.nedges) + n.iedges; |
|---|
| 312 | int swap = adjncy.get(k); |
|---|
| 313 | adjncy.set(k, adjncy.get(j)); |
|---|
| 314 | adjncy.set(j, swap); |
|---|
| 315 | swap = weights.get(k); |
|---|
| 316 | weights.set(k, weights.get(j)); |
|---|
| 317 | weights.set(j, swap); |
|---|
| 318 | } |
|---|
| 319 | } |
|---|
| 320 | } |
|---|
| 321 | |
|---|
| 322 | |
|---|
| 323 | @Override |
|---|
| 324 | public Graph clone() { |
|---|
| 325 | Graph g = new Graph(); |
|---|
| 326 | g.adjncy = new ArrayList<Integer>(); |
|---|
| 327 | for(int i = 0; i < adjncy.size(); i++) { |
|---|
| 328 | g.adjncy.add(adjncy.get(i)); |
|---|
| 329 | } |
|---|
| 330 | |
|---|
| 331 | g.weights = new ArrayList<Integer>(); |
|---|
| 332 | for(int i = 0; i < weights.size(); i++) { |
|---|
| 333 | g.weights.add(weights.get(i)); |
|---|
| 334 | } |
|---|
| 335 | |
|---|
| 336 | g.vtxs = new ArrayList<NodeInfo>(); |
|---|
| 337 | for(int i = 0; i < vtxs.size(); i++) { |
|---|
| 338 | g.vtxs.add(vtxs.get(i).clone()); |
|---|
| 339 | } |
|---|
| 340 | |
|---|
| 341 | g.index = new HashMap<Integer, Integer>(); |
|---|
| 342 | Iterator<Entry<Integer,Integer>> i = index.entrySet().iterator(); |
|---|
| 343 | while(i.hasNext()) { |
|---|
| 344 | Entry<Integer,Integer> entry = i.next(); |
|---|
| 345 | g.index.put(entry.getKey(), entry.getValue()); |
|---|
| 346 | } |
|---|
| 347 | |
|---|
| 348 | g.label = new HashMap<Integer, Integer>(); |
|---|
| 349 | i = label.entrySet().iterator(); |
|---|
| 350 | while(i.hasNext()) { |
|---|
| 351 | Entry<Integer,Integer> entry = i.next(); |
|---|
| 352 | g.label.put(entry.getKey(), entry.getValue()); |
|---|
| 353 | } |
|---|
| 354 | |
|---|
| 355 | |
|---|
| 356 | return g; |
|---|
| 357 | } |
|---|
| 358 | } |
|---|